-mms-bitfields gcc和vc关于位域那点事

 

STOP! Bitfields 对齐 align

CPU访问内 存时,总是以其整数字长为单位读写。比如 x86 CPU 总是从4字节的整数倍数地址上,读取4字节数据,它不能随心所欲地从任何位置开始读取任意长度数据。为了效率考虑,默认情况下编译器总是让整数存放于其长度的整数 倍数地址上。在一个结构中,为了做到这一点,有时不得不浪费几个字节。

举个例子,我 们定义一个结构:

struct {
    char c;
    int i;
};

从字面上看, 这个结构的长度是5个字 节,但默认情况下编译器总是分配8个字节,是为了让 i 出现在偏移量 4 地址上。

位域 bitfields C 语言结构中的一个成员,可以指定该成员所占内存 的位数 bit。然而, 在位域的对齐方式上,GCCMSVC2个编译器产生了巨大的分歧。现在,我们将上面这个结构改成下面这样子:

struct {
    char c;
    int b: 1;
    int i;
};

我们在 c i 中插入了一个只占 1 位内存的整数。在 GCC 中,我们测试该结构的长度,发现仍然是 8 个字节,就是说 b 利用了 c i 间的空隙,而没有多占空间。然而在 VC 中我们会发现,结构长达 12 字节。也就是说 b 像其他所有整数一样,在4倍数地址上对齐了。

如果仅仅这样 还好办,不幸的是,如果你在b后面再插入一个位域 b2,长度还是12。而如果插入一个 short 型的位域,长度将变成16

其原因在于 VC 使用了一种古怪的对齐方式,且没有完整的文档 描述。基本上,VC 将 结构中相邻的相同数据结构位域组成位域组,然后每个位域组都默认要求按其数据类型对齐。另外还有许多不同的例外情况。这样的情况与任何一个普通 GCC 支持的 对齐模式都不同。对齐方式不同意味着什么呢?考虑一下,Windows 是用 VC 编译的,也就是说所有 Windows API 都使用 VC 对齐方式。而如果你用 MinGW GCC编译 Windows 程序,你对所有使用了位域的 Windows API 的调用都将出错!而我们的 GTK+ for Windows 显然也是使用了 这种对齐方式。

万幸的是,Windows GCC 在编译时补上了一个新的命令行开关,-mms-bitfields,使其使用 VC 兼容的对齐方式。 Borland 所携带的这个 MinGW GCC也有。而这个开关别的平台上的 gcc 则都没有。加上这个编译开关后生成的代码将与 VC 的代码有相同的行为特征。只是 Borland 自己好像还没有意识到包里的 gcc 有着这么重要的一个开关,我找遍 Build Options Explorer 也 没有找到有这个选项的勾可打。好在此时 BCBX 的开放性再次救了我们和它自己一命。在 Options 标签页的最下面,有一个 Other options and parameters 选项。填在里面的参数将被原 封不动地拷贝到命令行上。所以我们在里面写上:

-mms-bitfields
posted @ 2011-07-18 22:32  Lunaa  阅读(327)  评论(0编辑  收藏  举报