灵活数组成员(零长度数组)

4

关于GCC的零长度数组的解释:

当一个结构体是可变长度对象的头时,这种技术特别有用。这正是我的情况。此外,我还担心在堆中我的结构体的对齐方式。

在这种情况下,我仍然不太明白零长度数组的用处。它们与这种特殊情况有何关系?

编辑:

是不是我可以在里面放尽可能多的“数据”?


如果可以避免使用,不要使用这个gcc扩展。自C99以来,灵活数组的正确语法是在结构体的最后一个成员上使用一对空括号“[]”,而不是“[0]”。Gcc也支持这种表示法。 - Jens Gustedt
2个回答

2
基本上它允许您在结构体末尾拥有一个长度可变的数组:
struct X {
  int first;
  int rest[0];
};

数组大小为0实际上是无效的(尽管作为gcc扩展是允许的)。没有指定大小是正确的方式。 由于C语言不关心您是否访问了数组末尾之外的元素,因此您可以从未定义的数组大小开始,然后分配足够的内存以处理您实际需要的任意数量的元素:

struct X *xp = (struct X *)malloc(sizeof(struct X)+10*sizeof(int));
xp->rest[9] = 0;

嗯 - 所以这确实与两个问题都有关。 - darksky
3
好的,关于解释没问题,但是请不要使用语法[0](这是gcc的扩展),而是使用[](这是C99标准并且也被gcc支持)或者[1],这样至少可以给你定义行为。 - Jens Gustedt
[1] 会因为 FORTIFY_SOURCE 而崩溃。越界访问实际上是未定义的。[] 运行良好,[0] 不太可移植但应该可以在 gcc 上工作。 - domenukk

0

malloc()返回的内存将被分配给一个指向具有零长度数组成员的结构体的指针,这个内存是按照C99规范所要求的对齐方式进行对齐的。因此,使用malloc()从堆中分配的内存来覆盖具有零长度数组的结构体不会出现问题。

如果您试图将结构体覆盖在来自紧凑或非传统对齐数据源(例如文件头、内存映射硬件接口等)的原始缓冲区上,则可能会遇到麻烦。在这些情况下,使用零长度数组处理可变长度数据可能是一个坏主意,因为数据可能不按照平台的默认对齐参数进行对齐,因此偏移数组将不会产生正确的结果。


我正在实现malloc(),这就是为什么我自己担心对齐的原因。 - darksky
你是如何通过mmap实现malloc的?在某个时刻,你需要向操作系统请求内存,而该内存将被对齐。非传统对齐的内存可能是像打包或“原始缓冲区”数据源、内存映射硬件接口等东西。当我说“非传统”时,我指的是即使缓冲区可能由intchar等组成,你也不能简单地创建一个包含这些元素的结构体,将其覆盖在缓冲区上,并期望编译器添加的填充会干扰覆盖操作。 - Jason

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接