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

时间:2019-05-13 20:54:41

标签: c language-lawyer flexible-array-member

考虑以下示例:

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)所示:

  

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

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

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

1 个答案:

答案 0 :(得分:8)

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

因此,将其视为普通表达式,引用数组sz的{​​{1}}元素。根据引用的规范,不会对此进行评估,因此它取消引用(*((tfa*) NULL)).info的事实不会导致未定义的行为。它仅返回数组元素的大小,而大小与数组或索引的位置无关。这就是为什么它会在没有警告的情况下编译并且不会崩溃的原因。

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

sz