1

考虑以下示例:

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
}

演示

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

运算符产生其sizeof操作数的大小(以字节为单位),它可以是表达式或带括号的类型名称。大小由操作数的类型决定。结果是一个整数。如果操作数的类型是变长数组类型,则计算操作数;否则,不计算操作数,结果为整数常量

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

代码的行为是否定义良好?

4

1 回答 1

8

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

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

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

tfa *ptr = malloc(sizeof *ptr + sz * sizeof ptr->info[0]);
于 2019-05-13T21:09:34.917 回答