GNU C 中的零长数组
Posted 车子 chezi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GNU C 中的零长数组相关的知识,希望对你有一定的参考价值。
文章目录
什么是零长数组(Arrays of Length Zero)
如果我们在程序中定义一个零长度数组,你会发现除了 GCC 编译器,在其它编译环境下可能就编译通不过或者有警告信息。
咱们看一个很简单的例子:
int buffer[0];
int main(void)
printf("%d\\n", sizeof(buffer));
return 0;
你会发现,输出结果是 0
也就是说,长度为 0 的数组是不占用内存空间的。
零长数组的使用
但是,零长度数组一般不单独使用,它常常作为结构体的最后一个成员,构成一个变长结构体。我们看一个例子
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
struct line
short len;
char contents[0];
;
int main(void)
const char *txt = "hello";
int my_len = strlen(txt) + 1;
struct line *my_line =
(struct line *) malloc (sizeof (struct line) + my_len);
my_line->len = my_len;
memcpy(my_line->contents, txt, my_len);
printf("%s\\n",my_line->contents);
printf("sizeof struct line = %lu\\n", sizeof (struct line));
printf("address struct line = %p\\n", my_line);
printf("address of char contents[0] = %p\\n", &my_line->contents);
输出结果是:
hello
sizeof struct line = 2
address struct line = 0x8c8010
address of char contents[0] = 0x8c8012
注意:
- struct line 的大小是 2 个字节,说明零长数组 contents 确实不占用空间
- contents 数组的起始地址就在 short len 的后面;原因是数组的类型是 char,如果改成 int ,那么在 short len 的后面就有填充
- 我们可以通过结构体成员 contents 访问内存(代码 17-18 行)。contents 就好比是一个标签,代表着某个地址常量
- malloc 只调用了一次(第 15 行)
结合这个例子,零长数组的好处是,可以根据需要给 struct line
分配空间,
struct line *my_line = (struct line *) malloc (sizeof (struct line) + my_len);
想用多少,就追加多少。
零长数组和指针的区别
有人说,用指针也可以实现。比如
struct line
short len;
void *contents;
;
其实是有区别的:
- void *contents 是一个变量,本身是占用内存的
- 在使用的时候,contents 指向另外一块内存,也就是说还要调用一次 malloc
- contents 指向的内存和 struct line 占用的内存一般是不连续的
所以,零长数组的优势就体现出来了。
定义什么类型的零长数组
有人认为,结构体尾部的零长数组应该是 char 类型,好处是节省空间,不需要在它前面填充。其实不然,具体是什么类型根据应用来定。
比如 Linux 内核里面有个结构体——USB request block
struct urb
struct kref kref;
void *hcpriv;
atomic_t use_count;
atomic_t reject;
int unlinked;
...
int error_count;
void *context;
usb_complete_t complete;
struct usb_iso_packet_descriptor iso_frame_desc[0];
;
11:它使用的零长数组是 struct usb_iso_packet_descriptor
类型,而不是 char 类型。
参考资料
以上是关于GNU C 中的零长数组的主要内容,如果未能解决你的问题,请参考以下文章