【问题标题】:Using the sizeof operator in the initialization of a struct with a flexible array在具有灵活数组的结构的初始化中使用 sizeof 运算符
【发布时间】:2017-06-14 20:29:22
【问题描述】:

我想声明一个包含灵活数组成员的结构,然后在上面使用sizeof()。原型是:

typedef struct
{
    uint16_t    length;
    uint8_t     array[][2];
} FLEXIBLE_t;

然后我声明它:

const FLEXIBLE_t test = {
    .length = sizeof(test),
    .array = {  {   0,  1   },
                {   2,  3   },
                {   4,  5   },
                {   6,  7   },
                {   8,  9   } }
};

一切都可以编译(GCC),但是当我检查 test.length 时,它的值为 2,即它只计算 length 本身的 uint16_t

如何在编译时计算结构体的大小?看来编译器使用的是原型而不是具体实例。

【问题讨论】:

  • 啊,等等,标准的 6.7.2.18 似乎暗示这个声明是无效的,即使编译器接受它。
  • 查看 .map 文件,似乎 GCC 已为结构分配了正确的空间量并按照我的预期填充了它。
  • 如果你在运行时计算,什么是 sizeof 测试?
  • 请注意,如果在没有static 限定符的函数内部定义了testconst 不重要),则 GCC 不允许初始化具有灵活数组成员的结构( FAM)。如果变量具有文件范围或标记为static,则作为扩展的 GCC 允许初始化。
  • @Vagish,sizeof 是一个编译时间常数。

标签: c arrays struct sizeof flexible-array-member


【解决方案1】:

GCC 允许将灵活数组初始化为扩展:https://gcc.gnu.org/onlinedocs/gcc-4.4.0/gcc/Zero-Length.html

但是,sizeof() 遵循 C 标准,并认为结构中的灵活数组的大小为零。在任何情况下,当尝试在结构的初始化程序中使用 sizeof() 时,该结构在该阶段是不完整的,并且最终大小尚不清楚。只有原型的大小及其零长度的灵活数组是已知的。

大小在编译时是已知的,只是在结构初始化之后才知道。在这种情况下,GCC 的 __builtin_object_size() 将计算为数字常量,但必须从函数中调用,因为它并不总是常量,因此不能在初始化程序中使用。

所以.length必须在运行时赋值,但至少被赋值的值编译成一个常量:

test.length = __builtin_object_size(test, 0);

【讨论】:

  • 即使是全局变量,在运行时评估灵活数组部分时,您仍然会得到 0 大小,这是后期阶段。
【解决方案2】:

sizeof 忽略灵活数组成员,因为灵活数组成员不占用结构内的空间。

C11-§6.7.2.2/18

作为一种特殊情况,具有多个命名成员的结构的最后一个元素可能具有不完整的数组类型;这称为灵活数组成员。 在大多数情况下,灵活数组成员被忽略。特别是,结构的大小就像省略了灵活的数组成员,只是它可能具有比省略所暗示的更多的尾随填充。 [...]

请注意,标准 C 不允许像在您的代码中那样进行灵活的数组成员初始化。它将调用未定义的行为(参见 §6.7.2.2 第 20 和 21 段)。虽然 GCC 允许这是 extension:

GCC 允许对灵活的数组成员进行静态初始化。这相当于定义一个包含原始结构的新结构,后跟一个足够大的数组来包含数据。

【讨论】:

  • 确实,请参阅我对这个问题的评论,我认为即使 GCC 对此声明很满意,声明也可能无效。
  • @ゼーロ; GCC 允许它作为扩展。
【解决方案3】:

sizeof() 运算符返回的大小(几乎)忽略了灵活数组。

根据C Standard, 6.7.2.1 Structure and union specifiers, paragraph 18

作为一种特殊情况,结构的最后一个元素具有多个 命名成员可能具有不完整的数组类型;这被称为 灵活的数组成员。在大多数情况下,柔性阵列 成员被忽略。 特别是结构的大小 就好像灵活数组成员被省略了,除了 它可能有比省略所暗示的更多的尾随填充。

【讨论】:

    【解决方案4】:

    灵活的数组成员不计入大小:

    ... 尤其是结构的大小好像是灵活的 数组成员被省略,除了它可能有更多的尾随 比省略所暗示的填充。

    除了大小问题之外,您的代码在 C 中还有未定义的行为。不能像那样初始化灵活的数组成员。从这个意义上说,Gcc 可能有一个扩展,但这不是可移植的。

    【讨论】:

      猜你喜欢
      • 2020-07-18
      • 2014-06-12
      • 2013-11-13
      • 1970-01-01
      • 1970-01-01
      • 2013-07-27
      • 1970-01-01
      • 2012-03-25
      • 2020-04-13
      相关资源
      最近更新 更多