Pav*_*kin 4 c typedef declaration language-lawyer variable-length-array
typedef VLA 是否需要计算大小表达式?
int f(void);
int main(void)
{
typedef int (T) [ f() ]; // is f required to be evaluated ?
T x;
return sizeof x;
}
Run Code Online (Sandbox Code Playgroud)
指向 VLA 的typedef指针是否需要计算大小表达式?
int f(void);
int main(void)
{
typedef int (*T) [ f() ]; // is f required to be evaluated ?
T x;
return sizeof x;
}
Run Code Online (Sandbox Code Playgroud)
UPD。在 isvisible 的定义中f,那么对它的调用可能会被优化掉:
int f(void)
{
return 4;
}
int main(void)
{
typedef int (*T) [ f() ];
return sizeof(T);
}
Run Code Online (Sandbox Code Playgroud)
生成的代码(GCC 和 LLVM):
main:
mov eax, 8
ret
Run Code Online (Sandbox Code Playgroud)
这是预期的,因为没有真正需要调用f来确定指针的大小。
根据 C 标准(\xc2\xa76.7.8 类型定义)
\n\n\n3 在存储类说明符为 typedef 的声明中,每个声明符将一个标识符定义为 typedef 名称,该名称以 6.7.6 中描述的方式表示为该标识符指定的类型。每次按执行顺序到达 typedef 名称的声明时,都会对与可变长度数组声明符关联的任何\n数组大小表达式进行求值。
\n
C 标准中有一个例子
\n\n\n8 示例 5 如果 typedef 名称表示可变长度数组类型,则数组的长度在定义 typedef 名称时固定,而不是每次使用时固定:
\n
void copyt(int n)\n{\n typedef int B[n]; // B is n ints, n evaluated now\n n += 1;\n B a; // a is n ints, n without += 1\n int b[n]; // a and b are different sizes\n for (int i = 1; i < n; i++)\n a[i-1] = b[i];\n}\nRun Code Online (Sandbox Code Playgroud)\n这是一个演示程序。
\n#include <stdio.h>\n\nint f( void )\n{\n static int n;\n \n return ++n;\n}\n\nvoid g( void )\n{\n typedef int ( *T )[ f() ];\n \n T p;\n \n printf( "sizeof( *p ) = %zu\\n", sizeof( *p ) );\n}\n\nint main(void) \n{\n for ( size_t i = 0; i < 10; i++ )\n {\n g();\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n程序输出是
\nsizeof( *p ) = 4\nsizeof( *p ) = 8\nsizeof( *p ) = 12\nsizeof( *p ) = 16\nsizeof( *p ) = 20\nsizeof( *p ) = 24\nsizeof( *p ) = 28\nsizeof( *p ) = 32\nsizeof( *p ) = 36\nsizeof( *p ) = 40\nRun Code Online (Sandbox Code Playgroud)\n