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,我期望这会导致崩溃。
代码的行为是否定义正确?
(*((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)