Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does alignment work with pointers to zero-sized arrays?

Tags:

c

gcc

struct

sizeof

I was investigating some code I saw that deals with 0-size arrays. Specifically, they are used in the case of dynamically allocated size of a struct such as in https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html

Specifically, this is the code in Callgrind:

struct _EventGroup {
    int size;
    const char* name[0];
};

I was playing around with this, using gcc 4.1.2 on a 64-bit Red Hat, and noticed that the sizeof function returns a size of 8 bytes for the entire struct _EventGroup when the name field is a pointer. Now if I change it to:

struct _EventGroup {
    int size;
    const char name[0];
};

I get 4 bytes because gcc identifies the 0-size array as taking up no space, and the int as taking up 4 bytes. That makes sense. If I then change it to:

struct _EventGroup {
    int size;
    const char* name;
};

sizeof returns 16 bytes because the char* takes up 8 bytes in a 64 bit system, and the int has to get padded to 8 bytes. This makes sense. Now, if I do one last change:

struct _EventGroup {
    const char* name[0];
};

I get 0 bytes because gcc is detecting my zero-size array. What I want clarified is what's happening in the first case I presented. How much space is gcc allocating for a pointer to a zero size array and why? I'm asking because this code seems designed to be efficient with memory allocation, however it would make sense that gcc either gives the pointer a size of 0 bytes if it detects it points to essentially nothing, or 8 bytes if it is being treated as a normal pointer. Alignment would dictate that I get either 4 bytes or 16 bytes with my original struct. Why am I getting 8 bytes?

like image 544
Mike Lui Avatar asked Sep 30 '22 06:09

Mike Lui


1 Answers

Gcc is adding the right amount of padding such that if you actually allocate extra space for the array, the pointer &(eventGroup->name) will be properly aligned.

It seems you're on a platform that has 4-byte ints and 8-byte pointers, so this means you have:

bytes 0-3   -- the int
bytes 4-7   -- padding
bytes 8-15  -- where the first (char *) would be stored, 8-byte aligned

Since it's actually an array of zero size, you don't actually have that first char *, but you do have the padding. Hence, the struct has size 8.

In your second example, there is no alignment requirement for a one-byte char, so you have:

bytes 0-3   -- the int
byte  4     -- where the first (char) would be stored, "1-byte aligned"

Again, no actual char in the struct, so it has size 4.

like image 169
danfuzz Avatar answered Oct 03 '22 01:10

danfuzz