🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] ## 缘由 最近在看redis的源码,刚开始看sds,看到这块代码 ``` struct __attribute__ ((__packed__)) sdshdr5 { unsigned char flags; /* 3 lsb of type, and 5 msb of string length */ char buf[]; }; ``` 好奇为什么使用 `char buf[]`,而不用`char *buf`,找到答案记录一下。 ## struct中的char*和char数组有什么区别 常用来构成缓冲区。比起指针,用空数组有这样的优势: * 不需要初始化,数组名就是所在的偏移,当数组名作为函数参数的时候,也就是指向第一个元素的指针。 * 空数组不占用内存, 但是指针需要占用int长度的空间,不同平台,占用大小不一样。 * 内存连续性 * 分配内存时:如果使用空数组,则可以使用 `malloc(sizeof(structXXX) + buf_len)`的方式来分配一段连续的内存。`buf_len`可以直接作为 缓冲区的长度。但是如果使用的是指针,则需要额外的去给指针赋值。而此时的内存与结构体的内存已经不连续,要分别申请和释放。 * 在释放内存时,如果用数组,则一次性释放;如果用的是指针,则需要先释放struct中的指针,再释放结构体,不可以颠倒。 >结构体中最后一个成员为`[1]`长度数组的用法:与长度为`[0]`数组的用法相同,改写为`[1]`是出于可移植性的考虑。有些编译器不支持`[0]`数组,可将其改成`[]`或`[1]`.一般使用`char []`. ## 代码示例: ``` #include <stdlib.h> #include <stdio.h> struct __attribute__ ((__packed__)) t_char1 { char a; char b[]; }; struct __attribute__ ((__packed__)) t_char2 { char a; char* b; }; int main() { char a = 0; char a1[]={}; char *b = &a; t_char1 c; t_char2 d; printf("char: %d, char*: %d, char[]: %d\n", sizeof(a), sizeof(b), sizeof(a1)); printf("t_char1: %d, c.a: %p, c.b: %p\n", sizeof(c), &c.a, c.b); printf("t_char2: %d, d.a: %p, d.b: %p\n", sizeof(d), &d.a, d.b); } ``` >`__attribute__ ((__packed__))`的作用是为了取消内存对齐。 编译输出 ``` $ g++ -o test main.cc -std=c++11 $ ./test char: 1, char*: 8, char[]: 0 t_char1: 1, c.a: 0x7ffd906865b6, c.b: 0x7ffd906865b7 t_char2: 9, d.a: 0x7ffd906865a0, d.b: 0xa000000000004006 ``` 总结: * `struct t_char1`中空数组没有分配内存,sizeof(c)-sizeof(a) = 1-1=0; `struct t_char2`中指针的内存占用了八字节 。 * 通过观察得到,在`struct t_char1`中, 空数组虽然不占用内存,但是可以获取结构体尾部的地址。 * 在结构体中更推荐使用`char`空数组。