【问题标题】:Flexible array member of unnamed struct未命名结构的灵活数组成员
【发布时间】:2019-05-13 20:54:40
【问题描述】:

考虑以下示例:

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,我预计这会导致崩溃。

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

【问题讨论】:

  • 这里的括号太多,但看起来 sizeof-ed 表达式不是弹性数组,而是它的元素之一。
  • 引用提到 VLA 不是灵活的数组。
  • 你应该使用sz * sizeof(ptr->info)
  • 是的,看起来是这样。 ....info[sz] 是数组的一个元素,而不是数组本身。
  • 由内而外 :) ((tfa*) NULL) 的类型为 tfa*(*((tfa*) NULL)) 的类型为 tfa。这整件事.info 是你的数组。并且添加 [sz] 正在对其进行索引。

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


【解决方案1】:

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

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

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

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

【讨论】:

  • sizeof ptr->info 这应该是sizeof ptr->info[0]
  • 即使sizeof 操作数是一种类型,灵活数组成员也不是变长数组。
  • @EricPostpischil 但是如果灵活的数组成员类似于int info[],你可以写成sizeof(int[sz])。这就是规范所讨论的符号。
  • @EricPostpischil 弹性数组成员类型不完整,变长数组类型完整。
  • @SomeName:你想说什么?
猜你喜欢
  • 1970-01-01
  • 2011-07-25
  • 2011-03-04
  • 1970-01-01
  • 2020-04-13
  • 2019-10-21
  • 1970-01-01
  • 2012-11-22
  • 2012-09-22
相关资源
最近更新 更多