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

Som*_*ame 1 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
}
Run Code Online (Sandbox Code Playgroud)

演示

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

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

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

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

Bar*_*mar 8

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

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

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

tfa *ptr = malloc(sizeof *ptr + sz * sizeof ptr->info[0]);
Run Code Online (Sandbox Code Playgroud)