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
.
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).