This topic contains 2 replies, has 2 voices, and was last updated by Anonymous 3 years, 10 months ago.
June 9, 2011 at 5:40 AM #82154
The size of this structure is 6 bytes and offset of u is 4 bytes, which suggests that unsigned bitfield is also tightly packed..
but if we change the size of unsigned bitfield to 15, the size becomes 8 and offset of u becomes 6,
further, changing unsigned bitfield to 17, size becomes 9 and offset of u becomes 7…
Explain this behavior..
Here is the code to test it..
#define offset(a,b) (size_t)(&(((a*)(0))->b))
l = offset(struct emp,u);
printf("%d %d",sizeof(struct emp),l);
June 9, 2011 at 11:20 AM #107834
It varies from compiler to compiler. Bitfields are one key programming construct that ruins the portability. They are unavoidable in low level programming. Here is the explanation.
Read the article http://geeksforgeeks.org/?p=9705 prior to moving forward.
On few compilers irrespective of bit-field range (constant numbers) they are governed by the alignment requirements of data types. Under such case the size of structure ‘emp’ becomes 12 bytes and offset of ‘u’ is always 8.
The behaviour that your are describing is appearing on GCC compiler (V4.5.2 on Ubuntu). Irrespective of integral data types being used, it is optimizing the packing of bits (that’s what bit-fields are meant for) as maximum as possible without compromising on alignment.
Note that we can’t mention bit-field size greater than the bits occupied by corresponding data type. For example char is 8 bits, short is 16 bits, int is 32 bits, etc… (on 32 bit machine).
The first member is char, and occupies one byte. Second member also character with demand of 7 bits, so they both occupy consecutive two bytes from the base address of array.
Third member is char, and demanding 2 bits. The second byte has room of 1 bits which forces the allocation of third member on next byte. This way we need three bytes, with one hole in second byte and room for next 6 bits in third byte.
Let us see each case.
case 1: (int : 14)
The forth member is demanding 14 bits, and 6 bits left in the third byte. So, it can make use of these 6 bits and the next byte. Even though the data type is int (which has alignment of 4 bytes), we just need two bytes to store these bit-fields. It means a ‘short int’ type is sufficient. That causes the total size to be 6 bytes, and offset at 4.
case 2: (int : 15)
Same analogy applies. We can’t make use of previous 6 bits left in byte three. It must go to next byte. Since the size is 15 bits, and minimum we need type of ‘short int’ which 2 bytes in size. The next byte is left open as padding, and the 15 bites are allocated in byte 5 and 6.
case 3: (int : 17)
We need more than two bytes to allocate 17 bits, and compiler reserves bytes 5, 6 and 7 for these 17 bits. Byte 4 is left as padding. When reading these 17 bits, it needs to access the bytes 5, 6, 7 and 8, following by masking of byte 8. The byte 8 can be used to store the next member which char (u in above case).
But this kind of compiler degrades the performance, as there are many masking operation involved. It can be controlled via the compiler switches.
If the data types changes, the structure allocation and size varies. As said on start of the comment, the allocation requirements of bit-fields varies from compiler to compiler. Even the bit-field mapping based on little endian or big endian also compiler dependent.
Better avoid using bit-fields, unless space demands them. Let me know if I am missing anything.June 9, 2011 at 4:30 PM #107835
Yes, i got it..
That was really helpful !!
You must be logged in to reply to this topic.