之前在写redis当中的sds结构的时候,留了个坑,不晓得为啥人家sds头的结构体最后面有一个0长度的数组,文章链接在这里http://blog.chinaunix.net/uid-31422160-id-5795408.html
最近看linux内核代码的时候,发现内核当中有些链表也搞这一套,发现事情并不简单,于是痛定思痛,自己挖的坑,自己要填上,在网上找啊找啊找,终于找到了官方文档,这里自己翻译,权当给自己长点记性,英语比较不错的读者可以移步至:
0长数组实际上是一个gcc当中的一个扩展功能,它可以如下声明,但是其中的contents却不占用结构体的存储空间,而是指向紧挨着结构体的下一个字节
-
struct line {
-
int length;
-
char contents[0];
-
};
这里需要注意的是,0长数组只有定义在结构体的最后才会有用~
如果按照如下定义一个struct line结构, thisline->contents就指向了结构体后的首个字节
-
struct line *thisline = (struct line *)
-
malloc (sizeof (struct line) + this_length);
-
thisline->length = this_length;
由于gcc允许静态初始化这种结构,所以当遇见来回嵌套的情况,编译器不会懵x,但是多的话,看得人就会懵x了,比如下边这个还好的
-
struct f1 {
-
int x; int y[];
-
} f1 = { 1, { 2, 3, 4 } };
-
-
struct f2 {
-
struct f1 f1; int data[3];
-
} f2 = { { 1 }, { 2, 3, 4 } };
这样就会带来一个问题,就是嵌套的时候,如果里面的结构体有这种定义的非空扩展,如果对其进行修改,实际上会修改到上层结构的地址当中,造成各种各样不愿意发生的事情,所以gcc就不允许在使用这种扩展功能区静态初始化非顶端结构,比如下面:
-
struct foo { int x; int y[]; };
-
struct bar { struct foo z; };
-
-
struct foo a = { 1, { 2, 3, 4 } }; // Valid. a是顶端结构
-
struct bar b = { { 1, { 2, 3, 4 } } }; // Invalid. b里面的2,3,4是非顶端结构,且使用该扩展
-
struct bar c = { { 1, { } } }; // Valid. 虽然c里面的结构是扩展功能,但是其为空,所以允许
-
struct foo d[1] = { { 1, { 2, 3, 4 } } }; // Invalid. d表示一个数组,非顶端结构
阅读(312310) | 评论(0) | 转发(0) |