关于GCC的零长度数组的解释:
当一个结构体是可变长度对象的头时,这种技术特别有用。这正是我的情况。此外,我还担心在堆中我的结构体的对齐方式。
在这种情况下,我仍然不太明白零长度数组的用处。它们与这种特殊情况有何关系?
编辑:
是不是我可以在里面放尽可能多的“数据”?
关于GCC的零长度数组的解释:
当一个结构体是可变长度对象的头时,这种技术特别有用。这正是我的情况。此外,我还担心在堆中我的结构体的对齐方式。
在这种情况下,我仍然不太明白零长度数组的用处。它们与这种特殊情况有何关系?
编辑:
是不是我可以在里面放尽可能多的“数据”?
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;
[0]
(这是gcc的扩展),而是使用[]
(这是C99标准并且也被gcc支持)或者[1]
,这样至少可以给你定义行为。 - Jens Gustedt[1]
会因为 FORTIFY_SOURCE 而崩溃。越界访问实际上是未定义的。[]
运行良好,[0]
不太可移植但应该可以在 gcc 上工作。 - domenukkmalloc()
返回的内存将被分配给一个指向具有零长度数组成员的结构体的指针,这个内存是按照C99规范所要求的对齐方式进行对齐的。因此,使用malloc()
从堆中分配的内存来覆盖具有零长度数组的结构体不会出现问题。
如果您试图将结构体覆盖在来自紧凑或非传统对齐数据源(例如文件头、内存映射硬件接口等)的原始缓冲区上,则可能会遇到麻烦。在这些情况下,使用零长度数组处理可变长度数据可能是一个坏主意,因为数据可能不按照平台的默认对齐参数进行对齐,因此偏移数组将不会产生正确的结果。
malloc()
,这就是为什么我自己担心对齐的原因。 - darkskymmap
实现malloc
的?在某个时刻,你需要向操作系统请求内存,而该内存将被对齐。非传统对齐的内存可能是像打包或“原始缓冲区”数据源、内存映射硬件接口等东西。当我说“非传统”时,我指的是即使缓冲区可能由int
、char
等组成,你也不能简单地创建一个包含这些元素的结构体,将其覆盖在缓冲区上,并期望编译器添加的填充会干扰覆盖操作。 - Jason