So per the C compiler standard here:
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf
We find a failure to pin down requirements for exactly how bit-fields get implemented inside a C compiler. Apparently, as long as the bit-fields behave like any other scalar field, anything goes. The doc section 6.7.2.1-10 says:
"An implementation may allocate any addressable storage unit large enough to hold a bit-field. If enough space remains, a bit-field that immediately follows another bit-field in a structure shall be packed into adjacent bits of the same unit. If insufficient space remains, whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined. The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined. The alignment of the addressable storage unit is unspecified."
This looming freedom for the compiler seems to be a full-stop for many who claim "you cannot trust bit-fields", or "bit-fields are not portable." The alarm suggests a whole herd of compiler writers and CPU makers conspiring in a star chamber, just grinning and anxious to do some exotic bit-field sizing and alignments simply because the standard permits.
WHERE IS THE EVIDENCE for these crazy bohemian compiler/CPU designers who are dedicated to guaranteeing that bit-fields remain forever undependable and unportable? I want to see actual hard evidence of the green-men on mars.
I've attached straightforward C++ source code to tell the bit-field truth about any system with a C++ compiler. I am asking the community, NOT for opinion, but for hard output evidence for your system and compiler if it diverges from the results posted. If I had the ability to poll the entire C/C++ community for same/not-same vote compared to the posted results, I wonder what the percentages would be?
#include <stdio.h>
/*
A simple program to illustrate the bitfields actual internal compiled layout.
Results depend on machine architecture and compiler implementation and flags.
*/
typedef unsigned long long int ulli;
struct bitf
{
// field bits offset
ulli f0 : 1; // 0
ulli f1 : 2; // 1
ulli f3 : 3; // 3
ulli f7 : 4; // 6
ulli f15 : 5; // 10
ulli f31 : 6; // 15
ulli f63 : 7; // 21
ulli f127 : 8; // 28
ulli f255 : 9; // 36
ulli f511 :10; // 45
ulli end : 9; // 55
// 64
bitf():
f0 ( 0 )
,f1 ( 1 )
,f3 ( 3 )
,f7 ( 7 )
,f15 ( 15 )
,f31 ( 31 )
,f63 ( 63 )
,f127 ( 127 )
,f255 ( 255 )
,f511 ( 511 )
,end ( 0 )
{}
ulli get_shft() const
{
ulli bits=0;
bits <<= 9; bits |= 0;
bits <<=10; bits |= 511;
bits <<= 9; bits |= 255;
bits <<= 8; bits |= 127;
bits <<= 7; bits |= 63;
bits <<= 6; bits |= 31;
bits <<= 5; bits |= 15;
bits <<= 4; bits |= 7;
bits <<= 3; bits |= 3;
bits <<= 2; bits |= 1;
bits <<= 1; bits |= 0;
return bits;
}
ulli get_cast() const
{
ulli bits = *((ulli*)(this));
return bits;
}
};
int main()
{
bitf bf;
ulli shft = bf.get_shft();
ulli cast = bf.get_cast();
printf("sizeof(ulli) is %zu\n\n",sizeof(ulli));
printf("shft%scast\n\n",(shft==cast)?"==":"!=");
printf("BITS from MSB 63 (left) down to LSB 0 (right)\n");
printf(" : "); for(int i=63; i>=0; i--) printf("%c",(i%10)==0 ? i/10 +'0' : ' '); printf("\n");
printf(" : "); for(int i=63; i>=0; i--) printf("%d",i%10); printf("\n");
printf("shft: "); for(int i=63; i>=0; i--) printf("%llu",(shft>>i)&1); printf("\n");
printf("cast: "); for(int i=63; i>=0; i--) printf("%llu",(cast>>i)&1); printf("\n");
printf(" : ====----====----====----====----====----====----====----====----\n");
printf("shft: "); for(int i=15;i>=0;i--) printf("%4llx",(shft>>(i*4)&0xf)); printf("\n");
printf("cast: "); for(int i=15;i>=0;i--) printf("%4llx",(cast>>(i*4)&0xf)); printf("\n");
printf(" : ====----====----====----====----====----====----====----====----\n");
unsigned char *pb;
pb = (unsigned char*)(&shft);
printf("shft: "); for(int i=sizeof(shft)-1; i>=0; i--) printf("%8x", pb[i]); printf("\n");
pb = (unsigned char*)(&cast);
printf("cast: "); for(int i=sizeof(cast)-1; i>=0; i--) printf("%8x", pb[i]); printf("\n");
printf("\n");
printf("<ENTER>"); getchar();
return 0;
}
Results for Intel Core i7, Win10, VS2015, 64bit build
sizeof(ulli) is 8
shft==cast
BITS from MSB 63 (left) down to LSB 0 (right)
: 6 5 4 3 2 1 0
: 3210987654321098765432109876543210987654321098765432109876543210
shft: 0000000000111111111011111111011111110111111011111011110111011010
cast: 0000000000111111111011111111011111110111111011111011110111011010
: ====----====----====----====----====----====----====----====----
shft: 0 0 3 f e f f 7 f 7 e f b d d a
cast: 0 0 3 f e f f 7 f 7 e f b d d a
: ====----====----====----====----====----====----====----====----
shft: 0 3f ef f7 f7 ef bd da
cast: 0 3f ef f7 f7 ef bd da
<ENTER>