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

Does typedef (pointer to) VLA require evaluation of the size expression?

typedef VLA 是否需要计算大小表达式?

int f(void);
int main(void)
{
    typedef int (T) [ f() ];       // is f required to be evaluated ?
    T x;
    return sizeof x;
}

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

int f(void);
int main(void)
{
    typedef int (*T) [ f() ];      // is f is required to be evaluated ?
    T x;
    return sizeof x;
}

更新。在定义中f是可见的,那么对它的调用可能被优化掉:

int f(void)
{
    return 4;
}

int main(void)
{
    typedef int (*T) [ f() ];
    return sizeof(T);
}

生成的代码(GCC 和 LLVM):

main:
        mov     eax, 8
        ret

这是预期的,因为没有真正需要调用 f 来确定指针的大小。

根据 C 标准 (§6.7.8 Type definitions)

3 In a declaration whose storage-class specifier is typedef, each declarator defines an identifier to be a typedef name that denotes the type specified for the identifier in the way described in 6.7.6. Any array size expressions associated with variable length array declarators are evaluated each time the declaration of the typedef name is reached in the order of execution.

并且在 C 标准中有一个例子

8 EXAMPLE 5 If a typedef name denotes a variable length array type, the length of the array is fixed at the time the typedef name is defined, not each time it is used:

void copyt(int n)
{
    typedef int B[n]; // B is n ints, n evaluated now
    n += 1;
    B a; // a is n ints, n without += 1
    int b[n]; // a and b are different sizes
    for (int i = 1; i < n; i++)
        a[i-1] = b[i];
}

这是一个演示程序。

#include <stdio.h>

int f( void )
{
    static int n;
    
    return ++n;
}

void g( void )
{
    typedef int ( *T )[ f() ];
    
    T p;
    
    printf( "sizeof( *p ) = %zu\n", sizeof( *p ) );
}

int main(void) 
{
    for ( size_t i = 0; i < 10; i++ )
    {
        g();
    }
}

程序输出为

sizeof( *p ) = 4
sizeof( *p ) = 8
sizeof( *p ) = 12
sizeof( *p ) = 16
sizeof( *p ) = 20
sizeof( *p ) = 24
sizeof( *p ) = 28
sizeof( *p ) = 32
sizeof( *p ) = 36
sizeof( *p ) = 40