void main()
{
  struct bitfield
  {
    signed int a :3;
    unsigned int b :13;
    unsigned int c :1;
  };
  struct bitfield bit1 = { 2, 14, 1 };
  clrscr();
  printf("%d", sizeof(bit1));
  getch();
}
为什么大小为4字节?这些元素究竟是如何存储在内存中的?
几乎每个比特字段都是实现定义的.甚至"普通int"位字段的签名也是实现定义的; 它可能是签名或未签名的.字段的布局 - 无论它们是从包含'单元'(标准中使用的术语)中的最高有效位到最低有效位还是从最低到最高有效位是实现定义的.最大允许位字段的大小; 当一个位字段存储在一个新单元中时; 所有这些都是实现定义的.
例如,在使用GCC 4.8.1的Mac OS X 10.8.4上,可以证明struct bitfield问题的布局是a占用3个最低有效位(位0-2),b占用接下来的13位(3 -15),c占用下一个1位(16):
#include <stdio.h>
static void print_info(int v);
int main(void)
{
    int values[] =
    {
        0x55555555, 0xAAAAAAAA, 0x87654321, 0xFEDCBA98,
        0xFEDCBA90, 0xFEDCBA91, 0xFEDCBA92, 0xFEDCBA93,
        0xFEDCBA94, 0xFEDCBA95, 0xFEDCBA96, 0xFEDCBA97,
        0xFEDCBA98, 0xFEDCBAA0, 0xFEDCBAA8, 0x0000BAA0,
        0x0001BAA0, 0x00000008, 0x00000010, 0x00000018,
        0x0000FFF0, 0x0000FFF8,
    };
    for (size_t i = 0; i < sizeof(values)/sizeof(values[0]); i++)
        print_info(values[i]);
    return 0;
}
static void print_info(int v)
{
    union
    {
        unsigned int x;
        struct bitfield
        {
            signed int   a:3;
            unsigned int b:13;
            unsigned int c:1;
        } y;
    } u;
    u.x = v;
    printf("0x%.8X => %2d 0x%.4X %1X\n", u.x, u.y.a, u.y.b, u.y.c);
}
样本输出:
0x55555555 => -3 0x0AAA 1
0xAAAAAAAA =>  2 0x1555 0
0x87654321 =>  1 0x0864 1
0xFEDCBA98 =>  0 0x1753 0
0xFEDCBA90 =>  0 0x1752 0
0xFEDCBA91 =>  1 0x1752 0
0xFEDCBA92 =>  2 0x1752 0
0xFEDCBA93 =>  3 0x1752 0
0xFEDCBA94 => -4 0x1752 0
0xFEDCBA95 => -3 0x1752 0
0xFEDCBA96 => -2 0x1752 0
0xFEDCBA97 => -1 0x1752 0
0xFEDCBA98 =>  0 0x1753 0
0xFEDCBAA0 =>  0 0x1754 0
0xFEDCBAA8 =>  0 0x1755 0
0x0000BAA0 =>  0 0x1754 0
0x0001BAA0 =>  0 0x1754 1
0x00000008 =>  0 0x0001 0
0x00000010 =>  0 0x0002 0
0x00000018 =>  0 0x0003 0
0x0000FFF0 =>  0 0x1FFE 0
0x0000FFF8 =>  0 0x1FFF 0
不是完全随机选择测试值.从测试值0xFEDCBA90到0xFECBA97,我们可以看到最低有效3位包含a.从测试值0x0000BAA0和0x0001BAA0,我们可以看到第17位(或第16位)包含c.从测试值0x00000008到0x0000FFF8,我们可以看到位3-15包含b.
但是,必须指出的是,该代码在理论上是可辩论的; 因为代码写入u.x然后读取u.x和u.y.a,u.y.b并且u.y.c,它不访问最后写到工会,这是严格未定义行为的成员.在实践中,它"始终"有效(我没有听说过它不起作用的系统 - 从技术上来说不可能存在一个不起作用的系统).
这种布局不是任何想象力的唯一可能的布局.但是,我无法访问演示替代布局的编译器或系统.
在ISO/IEC 9899:2011中,第6.7.2.1节结构和联合说明符说:
11实现可以分配任何足够大的可寻址存储单元来保存位域.如果剩余足够的空间,则紧跟在结构中的另一个位字段之后的位字段将被打包到相同单元的相邻位中.如果剩余的空间不足,则是否将不适合的位域放入下一个单元或重叠相邻单元是实现定义的.单元内的位域分配顺序(高阶到低阶或低阶到高阶)是实现定义的.未指定可寻址存储单元的对齐.
12没有声明符但只有冒号和宽度的位字段声明表示未命名的位字段.126)作为一种特殊情况,宽度为0的位域结构成员表示不再将其他位字段打包到放置了前一位域(如果有的话)的单元中.
126)未命名的位字段结构成员对于填充符合外部强加的布局很有用.
问题中结构的略微变化是:
struct exegesis
{
    signed int   a:3;
    unsigned int  :0;
    unsigned int b:13;
    unsigned int  :0;
    unsigned int c:1;
};
此结构的大小为12(与之前的编译器/平台相同).此平台上位字段的存储单元为4个字节,因此匿名零宽度字段将启动一个新的存储单元.  a存储在第一个4字节单元的最低有效3位中; b在第二个4字节单元的最低有效13位中; 并且c在第三个4字节单元的最低有效位中.如标准引用中所述,您也可以使用大于0的匿名位字段.
位字段如何存储在内存中取决于实现。
一个可能的原因是,具有 17 位的位字段应该至少包含 3 个字节,但编译器选择将其填充到 4 个字节。
同样,关于位字段的几乎所有内容都依赖于实现,包括它们的大小和内存布局。
最后,不要使用void main,永远留在int main