char pointer not the same to char array?

121 Views Asked by At

Reading the source code of Redis:

struct sdshdr {
    int len;
    int free;
    char buf[];
};

I found that char buf[] could not be replace with char *buf, in the sense that char* buf would increase the size of struct.

But I don't see why, would anyone shed some light on this?


Edit: I've tested it on my x86_64 Ubuntu(3.2.0-23-generic) with gcc 4.6.3 like this:

printf("sdshdr len = %zu\n", sizeof(struct sdshdr));

With char buf[] it outputs sdshdr len = 8 and sdshdr len = 16 with char *buf.

1

There are 1 best solutions below

0
On BEST ANSWER

The way the buf member is declared is taking advantage of a C99 feature called flexible arrays, the main advantage is to gain the use of variable length array like features inside a struct. Since buf is declared without a size it occupies no space until you explicitly allocate it when dynamically allocating a struct sdshdr *.

It is more efficient than using a char * since if buf was a char * we would have to perform two dynamic allocations, first for a struct sdshdr * and then again for buf and the pointer itself would require additional space. This is cleaner since the allocation either succeeds or fails as a unit and cleaning up is simpler since only one free is required. We also gain locality of data since the whole structure is allocated in a block and does not require a separate dereference to access buf.

The draft C99 standard in section 6.7.2.1 has a nice example that shows how to use this feature:

EXAMPLE After the declaration:

   struct s { int n; double d[]; };

the structure struct s has a flexible array member d. A typical way to use this
is:

    int m = /* some value */;
    struct s *p = malloc(sizeof (struct s) + sizeof (double [m]));

and assuming that the call to malloc succeeds, the object pointed to by p
behaves, for most purposes, as if p had been declared as:

     struct { int n; double d[m]; } *p;

(there are circumstances in which this equivalence is broken; in particular, the
 offsets of member d might not be the same).