类似的问题,但特定于打包的结构: Why would the size of a packed structure be different on Linux and Windows when using gcc?
我正在为Linux和Windows构建一个共享库,需要通过网络连接处理结构良好的数据。我在Linux上使用gcc 4.8.2,并使用i686-pc-mingw32-gcc 4.8.1对Windows目标进行交叉编译。
我已经制作了这个小程序来演示这个问题(请注意GCC属性已被注释掉,留待参考):
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
typedef uint16_t word_t;
typedef enum //__attribute__((__packed__))
{
PRIO_0 = 0,
PRIO_1,
PRIO_2,
PRIO_3,
PRIO_4,
PRIO_5,
PRIO_6,
PRIO_7,
}
prio_t;
typedef enum //__attribute__((__packed__))
{
FLAG_A = 0,
FLAG_B,
}
flag_t;
typedef struct //__attribute__((__packed__))
{
word_t id : 8;
prio_t prio : 3;
flag_t flag_1 : 1;
flag_t flag_2 : 1;
flag_t flag_3 : 1;
flag_t flag_4 : 1;
word_t spare : 1;
}
recd_t;
int main(int argc, char *argv[])
{
#define NAME_WIDTH 32
printf("%-*s = %lu\n", NAME_WIDTH, "sizeof(prio_t)", (unsigned long)sizeof(prio_t));
printf("%-*s = %lu\n", NAME_WIDTH, "sizeof(flag_t)", (unsigned long)sizeof(flag_t));
printf("%-*s = %lu\n", NAME_WIDTH, "sizeof(recd_t)", (unsigned long)sizeof(recd_t));
return 0;
}
我使用以下方法编译Linux:
gcc -g -Wall test.c -o ./test
Windows:
i686-pc-mingw32-gcc -g -Wall test.c -o ./test.exe
我觉得很直白。在Linux上运行时,输出就是我所期望的:
sizeof(prio_t) = 4
sizeof(flag_t) = 4
sizeof(recd_t) = 4
但在Windows上:
sizeof(prio_t) = 4
sizeof(flag_t) = 4
sizeof(recd_t) = 12
那么Windows尺寸的处理是什么?在这种情况下,为什么它们与Linux不同?
我最终需要打包这些枚举和结构,但这个问题出现在任何打包之前。启用后,结果类似:
Linux的:
sizeof(prio_t) = 1
sizeof(flag_t) = 1
sizeof(recd_t) = 2
视窗:
sizeof(prio_t) = 1
sizeof(flag_t) = 1
sizeof(recd_t) = 6
答案 0 :(得分:3)
C规范有一个信息性附件(附件J),它总结了未指明的行为,未定义的行为和实现定义的行为。这是关于位域的说法。
J.3实施定义的行为
需要符合要求的实施来记录其选择 本子条款中列出的每个领域的行为。下列 是实现定义的:
J.3.9结构,联合,枚举和位域
是否&#34;普通&#34; int位字段被视为有符号的int位字段或无符号的int位字段(6.7.2,6.7.2.1)。
除_Bool,signed int和unsigned int(6.7.2.1)以外的允许位字段类型。
- 是否允许原子类型用于位域(6.7.2.1)。
- 位字段是否可以跨越存储单元边界(6.7.2.1)。
- 单位内的位域分配顺序(6.7.2.1)。
- 结构的非位域成员的对齐(6.7.2.1)。除非由一个人写入二进制数据,否则这应该没有问题 实施由另一个人阅读。
- 与每个枚举类型兼容的整数类型(6.7.2.2)。
您可以得出自己的结论,但我不会在可移植的代码中使用位字段。
似乎在Windows上,编译器启动了一个新的&#34;单元&#34;每次类型改变。因此在解压缩的情况下,你有一个word_t(2个字节),后跟一个prio_t(4个字节),一个flag_t(4个字节),另一个word_t(2个字节),总共12个字节。打包时它的2,1,1,2共计6个。如果你将所有字段声明为uint16_t,你可能会在windows上获得正确的大小,但你仍然有<的问题em>&#34;单位&#34; 中位域分配的顺序是实现定义的。