typedef(指向)VLA 是否需要计算大小表达式?

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来确定指针的大小。

Vla*_*cow 7

根据 C 标准(\xc2\xa76.7.8 类型定义

\n
\n

3 在存储类说明符为 typedef 的声明中,每个声明符将一个标识符定义为 typedef 名称,该名称以 6.7.6 中描述的方式表示为该标识符指定的类型。每次按执行顺序到达 typedef 名称的声明时,都会对与可变长度数组声明符关联的任何\n数组大小表达式进行求值。

\n
\n

C 标准中有一个例子

\n
\n

8 示例 5 如果 typedef 名称表示可变长度数组类型,则数组的长度在定义 typedef 名称时固定,而不是每次使用时固定:

\n
\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}\n
Run 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}\n
Run Code Online (Sandbox Code Playgroud)\n

程序输出是

\n
sizeof( *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\n
Run Code Online (Sandbox Code Playgroud)\n