Struct hack - zero size array

#include <iostream> using namespace std; struct node1{ char b[3]; int c[0]; }; struct node2{ int c[0]; }; struct node3{ char b[3]; }; int main() { cout << sizeof(node1) << endl; // prints 4 cout << sizeof(node2) << endl; // prints 0 cout << sizeof(node3) << endl; // prints 3 } 

My question is: why does the compiler allocate 0 bytes for int c [0] in node2 but allocate 1 byte for its part of node1. I assume that this 1 byte is the reason why sizeof (node1) returns 4, since without it (for example, in node3) its size is 3 or because of filling #

Also trying to understand that node2 does not have enough space to store a pointer to an array (which will be allocated later in the code as part of a flexible hack array / structure?

+6
source share
4 answers

Yes, it's about padding / leveling. If you add __attribute__((__packed__)) to the end [useful when writing device drivers], you will get 3 0 3 for your output.

If node1 defines c [1], the size will be 8 not 7, since the compiler will align c with the border of int. With packed sizeof there will be 7

+2
source

Yes, adding makes a difference. The reason node1 has padding bytes, and node3 doesn't, lies in the typical use of zero-length arrays.

Zero-length arrays are usually used with casting: you put a larger object (possibly a variable) in a structure containing a zero-length array. Then you get access to the "rest" of a large object using an array of zero length, which for this purpose must be correctly aligned. The padding byte is inserted before the zero-size array, so int aligned. Since you cannot do this with node3 , padding is not needed.

Example:

 struct Message { char Type[3]; int Data[]; // it compiles without putting 0 explicitly }; void ReceiveMessage(unsigned char* buffer, size_t length) { if(length < sizeof(Message)) return; Message* msg = (Message*)buffer; if(!memcmp(msg->Type, "GET", 3)) { HandleGet(msg->Data, (length - sizeof(Message))/sizeof(int)); } else if.... 

Note: this is pretty hacky, but effective.

+2
source

c does not allocate one byte in node1 . Its due to additions added to b .

For b , which is easy to get with a 32-bit CPU, it has four bytes. 32-bit processors can read 4 consecutive bytes from memory at a time. To read three, they must read four, and then delete the one that is not needed. Therefore, to optimize this behavior, the compiler adds a struct to some bytes.

You can observe a similar compiler optimization when values ​​are pushed onto the stack (i.e. arguments or local variables are allocated). The stack is always maintained according to the size of the CPU data bus (typically 32 or 64 bits).

0
source
 int main() { cout << sizeof(node1) << endl; // prints 4 cout << sizeof(node2) << endl; // prints 0 cout << sizeof(node3) << endl; // prints 3 } 

the main function asks for the size of user-defined structures, not array members. sizeof () returns the number of bytes allocated for the structure, with 1 byte allocated to each character allocated in the character array. The character array is indeed a C-style string that ends with the sentinel character "\ 0". It probably includes a byte allocated for storing sentinel characters when evaluating sizeof (node1), since there is another variable after it, so it reads it, but does not include the sentinel element sizeof (node3), where the line and structure end

0
source

All Articles