5

I have a struct defined as:

struct smth
{
    char a;
    int b[];
};

When I call sizeof and offsetof on this struct:

cout << sizeof(struct smth) << endl;
cout << offsetof(struct smth, b) << endl;

Output is:

4
4

How come when the size of the stuct is 4 and char is using 1 byte, the offset of the int array is 4? Why is there some kind of padding? Also, why isn't the int array occupying any space at all?

bugra
  • 55
  • 5

3 Answers3

8

How come when the size of the stuct is 4 and char is using 1 byte, the offset of the int array is 4? Why is there some kind of padding?

There is padding because the C standard allows it; the compiler often aligns variables to improve performance.

Also, why isn't the second variable occupying any space at all (which seems like the case)?

It's a C99 flexible array member - that's the entire point of it. The idea is to allocate your structure something like:

struct smth *s = malloc(sizeof *s + 10 * sizeof s->b[0]);

And then you'd have a structure that operates as if b were a 10-element array.

Carl Norum
  • 219,201
  • 40
  • 422
  • 469
  • What kind of performance improvements does this allow? Just curious. – bugra Aug 17 '13 at 15:22
  • @biox6, some processors load instructions can only load words from word-aligned addresses. If you have a word at an unaligned address, you'd need to load each byte separately and recombine. – Carl Norum Aug 17 '13 at 15:23
  • Your allocation statement does not consider alignment constraints. In general it will fail to allocate the correct amount of memory. You would instead allocate a properly sized structure using `struct smth *s = malloc(offsetof(struct smth, b[10]));`. – IInspectable Aug 17 '13 at 15:48
  • @IInspectable, how so? `malloc` is required to return safely-aligned pointers, and the structure is laid out correctly. What's the difference? – Carl Norum Aug 17 '13 at 16:27
  • 1
    probably `10 * sizeof s->b[0]` – 6502 Aug 17 '13 at 18:06
  • I'm sorry, brain-lag. I had [something else altogether](http://blogs.msdn.com/b/oldnewthing/archive/2004/08/26/220873.aspx) in mind. Consider it an *alternative* way to calculate the size rather than a *correction*. The trailing zero-sized array being part of the struct ensures proper alignment. – IInspectable Aug 17 '13 at 18:52
3

Because the size of the member b is zero, and the compiler adds padding between the a and b members so that b is on a "word" boundary.

However, if I remember correctly having a flexible array in a structure like that is only valid C, not C++ except as a compiler extension.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • here is this `int b[]` equivalent to int *b? – Light Aug 17 '13 at 15:35
  • 2
    No it is not. `int* b` would make the `sizeof(smth)` larger, and the extra space would be where address of some int variable is to be stored. Instead, `int b[]` says the structure shall be allocated dynamically with some (unknown at compile time) number of integers as a single memory block. – mity Aug 17 '13 at 15:40
  • @mity How do you assign value(s) to the variable `b`,could you give me the assignment statement – Light Aug 17 '13 at 15:56
  • @Light See the answer from Carl Norum. – Some programmer dude Aug 17 '13 at 15:57
  • @Light: Given `struct smth *s = malloc(sizeof(*s) + 10*sizeof(*s->b));`, you can write `s->a = 'c'; s->b[0] = 0; s->b[9] = 9;`, etc. – Jonathan Leffler Aug 17 '13 at 15:58
2

Since OP comments that the question is C++:

struct smth
{
    char a;
    int b[];
};

An array like b[] is invalid in C++. The array must have fixed size. Variable length arrays are only valid in C99.

Assuming that your compiler supports it as extension, the array b[] has a size of zero, which makes the struct containing only a char member. The the rule of padding in struct works, padding the struct to a word, which is 4 bytes in your machine.

Yu Hao
  • 119,891
  • 44
  • 235
  • 294