1.位域(struct中的冒号)
struct中的冒号表示强行为某变量指定存储空间大小。例如:
typedef struct {
int a:1;
int b:2;
int c:5;
} AA;
在这个结构体之中,a只占1个bit空间,b占2个bit空间,c占5个bit空间。
因此,整个AA只占8个bit空间,即只占一个字节。
另外说明一点,即在一个byte之内a,b,c是从低向高取值的。
例如AA x;,其中x处地址存放的数据为10101010;
那么从右往左看,x.a将为0,x.b将为二进制的01,x.c将为二进制的10101。
那么输出sizeof(AA),得到的结果是否为1呢?另我大吃一惊的是,实际结果是4。
我们可以看到,如果不加冒号,这个结果应该是12,这说明我们添加的冒号还是有效的。那为什么输出结果是4呢?
2.#pragma pack(n)
这涉及到内存对齐的问题了。编译器为了方便CPU进行取址操作,会对struct中的数据分配空间时自动对齐。默认的对齐的字节数可以为1、2、4、8、16。
我们可以通过宏指令#pragma pack(n)来强行转换对齐的字节数大小。
例如:
typedef struct {
char a;
int b;
} AA;
因为内存对齐的原因,这个结构体所占空间为8。但是我们更改一下对齐方式,在最前面加入#pragma pack(2),
#pragma pack(2)
typedef struct {
char a;
int b;
} AA;
我们会发现sizeof(AA)现在的大小为6!这便是#pragma pack(n)的作用。
另外提醒一下,这里头的n必须为1、2、4、8、16才有效。另外,编译器将会在struct中空间最大的变量所占字节数与自定义的n之间取最小值来完成对齐。例如:
#pragma pack(8)
typedef struct {
short a;
short b;
} AA;
你认为输出将会为8?错了,输出为4,因为默认为2字节对齐,小于自定义的8。
还可以保存和恢复目前的对齐方式,语句分别是
#pragma pack(push)
#pragma pack(pop)
回到原来的问题上,sizeof(AA)输出为4就是因为对齐的原因。编译器检测到int参数的存在,因此将会默认4字节对齐。即使只占用了一个字节的空间,sizeof(AA)也将会输出4。
我们在最开始强制转换为1字节对齐,如下:
#pragma pack(1)
typedef struct {
int a:1;
int b:2;
int c:5;
} AA;
现在的sizeof(AA)就会输出1了。