struct hack - zero sized array

╄→尐↘猪︶ㄣ 提交于 2019-12-05 06:21:47

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

If node1 had defined c[1], the size is 8 not 7, because the compiler will align c to an int boundary. With packed, sizeof would be 7

Yes, padding makes the difference. The reason why node1 has a padding byte, while node3 doesn't, lies in the typical usage of zero-length arrays.

Zero-length arrays are typically used with casting: You cast a larger, (possibly variable-sized) object to the struct containing the zero-length array. Then you access the "rest" of the large object using the zero-length array, which, for this purpose, has to be aligned properly. The padding byte is inserted before the zero-sized array, such that the ints are aligned. Since you can't do that with node3, no padding is 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 rather hackish, but efficient.

cadaniluk

c doesn't allocate one byte in node1. Its because of the padding added to b.

For b, to be easily obtainable by a 32-bit CPU, it is four bytes big. 32-bit CPUs can read 4 consecutive bytes from memory at a time. To read three, they have to read four and then remove the one not necessary. Therefore, to optimize this behavior, the compiler padds the struct with some bytes.

You can observe similar compiler optimizations when values are pushed on the stack (that is, arguments or local variables are allocated). The stack is always kept aligned to the CPU's data bus size (commonly 32 or 64 bits).

int main() {

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

the main function queries the the size of the user defined structs, not of the array members. sizeof() will return the number of bytes allocated to the struct, with each character allocated in the character array being allocated 1 byte. A character array is really a C style string which is terminated by the sentinel character '\0'. It is likely to include the byte allocated to hold the sentinel character when evaluating the sizeof(node1) as there is another variable after it so it reads over it, but not include the sentinel in sizeof(node3) where the string and the struct terminates

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!