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

注意:

  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:零长度数组 - 知乎

以上是关于GNU C 中的零长数组的主要内容,如果未能解决你的问题,请参考以下文章

LintCode 2. 尾部的零

LintCode 尾部的零

LintCode #2 尾部的零

2. 尾部的零简单

LintCode 2. 尾部的零

2.尾部的零