今天在看 redis 源码的时候了解到一个不熟悉的名词 柔性数组
本着遇到问题解决问题,遇到疑惑解决疑惑的态度动手试试看看是不是和我想的那样。
在看到 SDS
动态字符串的时候,刚开始看到这个结构,就直接认为这个 buf
想到了 一个 char
类型的指针。
1 2 3 4 5 6
| struct __attribute__ ((__packed__)) sdshdr8 { uint8_t len; uint8_t alloc; unsigned char flags; char buf[]; };
|
然后就写 demo 测试.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| #include "stdlib.h" #include "stdio.h"
typedef unsigned short uint16_t;
struct __attribute__ ((__packed__)) sdshdr16 { uint16_t len; uint16_t alloc; unsigned char flags; char buf[]; };
int age = 12; int buf[4] = {1, 2, 3, 4}; int main() { struct sdshdr16 s; s.len = 1; s.alloc = 2; s.flags = 0b11; s.buf = (char *) malloc(sizeof(char) * 200); return 0; }
|
这里一直被卡在 s.buf = (char *) malloc(sizeof(char) * 200);
这里。
...
中途省略 n 多字
...
一直不知道原来,再回头看书,发现我忽视了最重要的一个关键词, 柔性数组。
终于了解了。
在 C99 中,结构中的最后一个元素允许是未知大小的数组,这就叫做柔性数组成员。在使用柔性数组成员时,需要注意如下几点:
- 结构中的柔性数组成员前面至少包含一个其他成员。
- 柔性数组成员允许结构中包含一个大小可变的数组。
- sizeof 返回的这种结构大小不包括柔性数组的内存。
- 包含柔性数组成员的结构用 malloc()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。
也就是说在给这个结构体分配内存的时候,不管内存分配多大,除了前面需要用到的,剩下的空间都是这个数组的。
验证一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| #include "stdlib.h" #include "stdio.h"
typedef unsigned short uint16_t;
struct __attribute__ ((__packed__)) sdshdr16 { uint16_t len; uint16_t alloc; unsigned char flags; char buf[]; };
int main() { struct sdshdr16 *s1 = (struct sdshdr16 *) malloc(sizeof(struct sdshdr16) + 27); struct sdshdr16 *s2 = (struct sdshdr16 *) malloc(sizeof(struct sdshdr16) + 27); printf("%d", sizeof(struct sdshdr16)); s1->len = 0; s1->alloc = 200; s1->flags = 0b11; for (int i = 0; i < 40; i++) { s1->buf[i] = 'a' + i % 26; } printf("\ns1->buf[40]: %d", &s1->buf[27]); printf("\ns2: %d", s2); s1->buf[43] = 31; printf("\ns2->len: %d", s2->len); return 0; }
|
这里验证了一下确实是这样的,目前给 s1 分配了 32 个字节,除了前面用到的 5 个字节,后面的 27 个字节都是给 buf
的
所以 buf[27]
的地址与 s2
的地址一样。因为 s1, s2
是一起分配的。所以在空间上是连续的。
这里需要注意的是,这里会在分配内存的时候会进行字节对齐,如果我这边给 buf 分配的不是 27 个字节,而是其他的,比如 40
个字节,加上结构体前面的 5 个字节,共 45 个字节,字节对齐的话,s2 应该从第 48 个字节起分配内存,也就是 buf[43]的地址为 s2 的地址。