C语言中的柔性数组

        前段时间在阅读nginx的源代码时,碰到一个之前从未碰到的问题,nginx定义的hash表中的元素的结构体:

typedef struct {
    void             *value;
    u_short           len;
    u_char            name[1];
} ngx_hash_elt_t;

        暂且不论各个成员的含义,u_short就是unsigned short,u_char就是unsigned char,那么u_char name[1];是个什么结构?为什么要这么定义它?在网上查了一下,才了解一二。这么定义它有两个好处:

1. 这个结构体是变长的,不仅限于ngx_hash_elt_t本身的大小。

2. 分配大小大于sizeof(ngx_hash_elt_t)的空间时,后续的空间与ngx_hash_elt_t的空间是连续的。

        在查询的过程中,碰到另一个更奇怪的问题:

typedef struct {
    short len;
    char  data[0];
} demo_t;

        char data[0];是个什么定义?再查了下这个东西,才知道它叫做柔性数组,常用于变长结构体,节省空间和提供便利的访问性。sizeof(demo_t)时,它本身不占空间,但是,如果像上述那样给demo_t后面分配了额外的空间后,那么我们就可以通过成员名访问它了。例子如下:

#include <stdio.h>
#include <malloc.h>
#include <string.h>

typedef struct {
  short len;
  char data[0];
} demo_t;

int main()
{
  const char *str = "hello world!";

  demo_t *p = (demo_t *)malloc(sizeof(demo_t) + strlen(str) + 1);
  memset(p->data, 0, strlen(str) + 1);
  memmove(p->data, str, strlen(str));

  printf("sizeof(demo_t) = %d, p->data = %s\r\n", sizeof(demo_t), p->data);
  free(p);

  return 0;
}

        上述的输出是:sizeof(demo_t) = 2; p->data = hello world!

        最后,看网上说只有GCC支持这种用法,但是上述的例子使用GCC 4.6.3和VS 2010都测试通过,这说明GCC和VS 2010都支持这种用法了。

        现在回过头来看看ngx_hash_elt_t中的u_char name[1];,在不使用它时,它占用一个字节,要使用它时,上述的例子中malloc一句不需要+1,因为它已经占用了一个字节,而memset一句不变,因为strlen(str)这么大的空间刚好可以放下str的内容,再加上末尾的'\0'就是strlen(str)+1了,相当于name[0]的空间放下了'\0'(只是比喻,非实际情况)。

猜你喜欢

转载自blog.csdn.net/winshining/article/details/50350548