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

注意:

  1. struct line 的大小是 2 个字节,说明零长数组 contents 确实不占用空间
  2. contents 数组的起始地址就在 short len 的后面;原因是数组的类型是 char,如果改成 int ,那么在 short len 的后面就有填充
  3. 我们可以通过结构体成员 contents 访问内存(代码 17-18 行)。contents 就好比是一个标签,代表着某个地址常量
  4. malloc 只调用了一次(第 15 行)

结合这个例子,零长数组的好处是,可以根据需要给 struct line 分配空间,

struct line *my_line = (struct line *) malloc (sizeof (struct line) + my_len);

想用多少,就追加多少。

零长数组和指针的区别

有人说,用指针也可以实现。比如

struct line {
  short len;
  void *contents;
};

其实是有区别的:

  1. void *contents 是一个变量,本身是占用内存的
  2. 在使用的时候,contents 指向另外一块内存,也就是说还要调用一次 malloc
  3. 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 类型。


参考资料

嵌入式C语言自我修养 05:零长度数组 - 知乎

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值