未命名结构的灵活数组成员

Flexible array member of unnamed struct

考虑以下示例:

typedef struct test_flex_arr{
    size_t sz;
    struct {
        int i;
        const char *path;
    } info[];
} tfa;

int main(void){
    size_t sz = 100;
    tfa *ptr = malloc(sizeof *ptr + sizeof (*((tfa*) NULL)).info[sz]);
    ptr->info[99].i = 10;
    printf("%d\n", ptr->info[99].i); //prints 10
}

DEMO

我预计这个程序会崩溃,但它运行得很好。按照指定 6.5.3.4(p2):

The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand. The result is an integer. If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant

sizeof ((*((tfa*) NULL)).info)[sz]的操作数类型是可变长度数组,因此应该计算操作数。但是对操作数的评估意味着取消引用 NULL 我预计会导致崩溃。

代码的行为是否定义明确?

(*((tfa*) NULL)).info[sz]不是变长数组类型,因为(*((tfa*) NULL)).info不是类型。

因此它将其视为普通表达式,引用数组 (*((tfa*) NULL)).infosz 元素。根据引用的规范,这不会被评估,因此它取消引用 NULL 的事实不会导致未定义的行为。它只是 returns 数组元素的大小,它不依赖于数组的位置或索引。这就是为什么它在没有警告的情况下编译并且不会崩溃的原因。

但这并没有产生预期的结果。您只会获得数组中一个元素的大小,而不是您实际需要为其分配 space 的 sz 元素。您需要将元素的大小乘以元素的数量。所以使用

tfa *ptr = malloc(sizeof *ptr + sz * sizeof ptr->info[0]);