43

我使用 sizeof 在 C 中获取结构的大小,但我得到的结果是出乎意料的。

struct sdshdr {
    int len;
    int free;
    char buf[];
};


int main(){
    printf("struct len:%d\n",(sizeof(struct sdshdr)));
    return 0;
} //struct len:8, with or without buf

我的问题是为什么不buf占用任何空间,为什么int类型的大小在 64 位 CPU 上仍然是 4?

这是来自的输出gcc -v

Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
Target: x86_64-apple-darwin14.4.0
Thread model: posix  
4

4 回答 4

53

[] 是一个灵活的数组成员。它们不计入结构的总大小,因为 C 标准明确表示:

6.7.2.1/18

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

这是有意设计的,因为灵活数组成员的目的是允许您在结构之后动态分配尾随数据。(当结构是文件头、协议头等时)

示例包括关于非标准 gcc 扩展和旧的 C99 之前的“struct hack”的讨论。

于 2015-07-09T13:25:32.767 回答
12

从 C99 开始,可以省略结构末尾的数组大小。出于该数组的目的,sizeof(struct)该数组的大小似乎为零(尽管它的存在可能会给结构添加一些填充),但其目的是使其长度灵活,即,在为结构分配空间时,必须分配所需数量的最后为数组提供额外的空间。(为避免超出范围,数组的实际分配长度应存储在某处。)

在 C99 之前,在结构的末尾有一个大小为 1(或在编译器允许的情况下为 0)的数组然后为其分配更多空间是一种相当常见的 hack,因此 C99 通过引入灵活数组明确允许这种做法没有给出大小的成员

于 2015-07-09T13:32:34.450 回答
2

作为 GNU c 扩展,您有零长度数组:

作为 GNU 扩展,元素的数量可以小到零。零长度数组可用作结构的最后一个元素,它实际上是可变长度对象的标头:

例如,考虑来自The gnu c manual 的这段代码

 struct line
 {
   int length;
   char contents[0];
 };

 {
   struct line *this_line = (struct line *)
     malloc (sizeof (struct line) + this_length);
   this_line -> length = this_length;
 }

在 ISO C99 中,您将使用灵活的数组成员,它在语法和语义上略有不同:

  • 灵活的数组成员被写为没有 0 的 contents[]。

  • 灵活数组成员的类型不完整,因此可能无法应用 sizeof 运算符。作为零长度数组的原始实现的一个怪癖,sizeof 的计算结果为零。

  • 灵活数组成员只能作为非空结构的最后一个成员出现。

  • 包含灵活数组成员的结构或包含此类结构的联合(可能是递归的)可能不是结构的成员或数组的元素。(但是,GCC 允许这些用途作为扩展。)

于 2015-07-09T13:21:44.143 回答
0

buf这是一个flexible array member 灵活数组成员的类型不完整,因此 sizeof 运算符可能不适用,而 , 的原始zero-length arrays实现sizeof evaluates to zero

于 2015-07-09T13:33:06.040 回答