4

I'm confused about sizeof() output in C. Say I have:

struct foo {
    char a;
    char b;
    char c;
    char d[0];
};

I would expect sizeof(struct foo) to be 4. However, it returns 3 after compiling with gcc. Also, when compiling the code with strict settings -pedantic-errors, I get compiler errors.

Can someone help me understand this behavior?

Lundin
  • 195,001
  • 40
  • 254
  • 396
marcantonio
  • 958
  • 10
  • 24
  • What if you change the `0` to `1` or higher ? – XBlueCode Sep 13 '19 at 15:53
  • 5
    Declaring an array with 0 elements is not valid C. It is accepted by GCC (and some other implementations) as an extension. – rici Sep 13 '19 at 15:54
  • Could you flag for this to be CW? It seems like a good C FAQ candidate. – S.S. Anne Sep 24 '19 at 22:14
  • I took the liberty to add some extra information to the post, since someone has now added this question to the [C FAQ](https://stackoverflow.com/tags/c/info). I hope you don't mind - it only means that your question will get positive extra attention. – Lundin Oct 23 '19 at 15:33

2 Answers2

8

An array size of 0 is not legal. Section 6.7.6.2p1 of the C standard regarding Array Declarators states:

In addition to optional type qualifiers and the keyword static , the [ and ] may delimit an expression or * . If they delimit an expression (which specifies the size of an array), the expression shall have an integer type. If the expression is a constant expression, it shall have a value greater than zero. The element type shall not be an incomplete or function type. The optional type qualifiers and the keyword static shall appear only in a declaration of a function parameter with an array type, and then only in the outermost array type derivation.

So because this violates a constraint, this definition invokes undefined behavior.

That being said, some compilers allow a zero length array as the last member of a struct as an extension. GCC does this. In this case, it works the same as a flexible array member.

The standard compliant way to do this is to leave the size blank:

struct foo {
    char a;
    char b;
    char c;
    char d[];
};

In both cases, the flexible array member is not included in the size of the structure, which is why you get 3 for the size instead of 4 (although the presence of padding in a struct is up to the implementation). This also means that such a struct cannot be a member of an array (at least not without some fishy manual pointer manipulation).

The way you would use such a struct would be to dynamically allocate space for it plus a number of elements of the last member. For example:

struct foo *my_foo = malloc(sizeof(*my_foo) + (sizeof(char) * number_of_elements));
dbush
  • 205,898
  • 23
  • 218
  • 273
  • 2
    It's not legal but actually implemented as a [GNU extension](http://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html). – Jack Sep 13 '19 at 15:54
  • Ah, that makes sense. So does gcc interpret this as a pointer to the end of the struct? – marcantonio Sep 13 '19 at 15:59
  • @marcantonio It actually points to the flexible array member which is after the other members. – dbush Sep 13 '19 at 16:03
  • The _flexible array member_ syntax was standardized in C99, but several compilers before that (e.g. GCC and MSVC) supported it with a pre-standard syntax of using 0 as the array length. Those compilers choke on the standard syntax. – Ian Abbott Sep 13 '19 at 16:05
1

char d[0] is an array of chars with size 0. Which means it doesn't take up any space, since sizeof(char) * 0 = 0.

3limin4t0r
  • 19,353
  • 2
  • 31
  • 52