在看《程序员面试宝典(第四版)》中,第53页,说到#pragma pack(n)的用法的时候,还是不怎么明白,百度了下,了解了一些,http://baike.baidu.com/link?url=T74KbntKrJWMgZ5nPI3Lbq9Z40fILcATqPqBVTOnvNpykIcd-iJxfiYgR07mM5c9y59oY6OLdXoWx6qcY0mih_ 这是百度百科的介绍,但是心中还是有疑惑,因此自己写了一小段程序,了解#pragma pack(n)的用法。也是我写人生中第一篇博客的目的。
程序:(vs2012)
#include<cstdio>
#include<iostream>
using namespace std;
#pragma pack(3)
struct s
{
short a;
char b;
short c;
double d;
}p;
#pragma pack()
int main()
{
printf("%d\n",sizeof(short));
printf("%d\n",sizeof(p));
printf("%x\n",&p.a);
printf("%x\n",&p.b);
printf("%x\n",&p.c);
printf("%x\n",&p.d);
return 0;
}
输出结果是:
2
16
15f220
15f222
15f224
15f228
解释一下,short是2字节;结构体struct s ,在栈中是16字节;然后分别是,a,b,c,d的地址;
先给出我总结的法则吧:1,#pragma pack(n),就像我程序里给的,n=3,编译器真的就按3字节对齐吗?不是的。对于不是1,2,4,8的不合理数字,都会使这个自定义字节对齐的作用无效;(可以试一下-1,0,3.5什么的,不会报错,但是等于没有#pragma pack(n));
2,n>8的时候编译器会怎么处理?直接无效,也就是说,等于没有写过#pragma pack(n)这个预处理一样。因为所有基本数据类型就多大为8字节的(据我了解,错求更正)。同理,若n<=8且比结构体中任何基本数据类型还大,也会失效的。
嗯,没了,这是自己总结的。
当然,还要加些自己看到的。
在没有自定义字节对齐长度的情况下,
1,结构体的内存分配是按定义变量的顺序安排内存的,这是一定的,而且是按照结构体内最长的变量的长度对齐的;
2,我们可以用《程序员面试宝典(第四版)》,第54页的方法:(例)
class B
{
private:
bool m_bTemp;
int m_nTemp;
bool m_bTemp2;
};
class C
{
private:
int m_nTemp;
bool m_bTemp;
bool m_bTemp2;
};
内存分布可以这样画:
class B:
|bool|----|----|----|
|-------int----------|
|bool|----|----|----|
class C:
|------int-----------|
|bool|bool|---|---|
所以,B占3x4=12字节;C占2x4=8字节。看出什么没有,首先按最大长度int(4字节),即默认为#pragma pack(4)。然后长度就是如上计算,而且即使是后面还有空余,但是内存还是认为被占用了;而且,每个变量都被置顶了。
以上经试验证明,如有错误求更正。
现在就用例子证明吧,先证明最前面的例子。
#pragma pack(3)//对于3这个不合理的数字,这种自定义会无效,即变为按最大长度double(8字节),即默认为#pragma pack(8)对齐。
struct s
{
short a;//4>2,不管用了。设地址为0,则占[0,1]
char b;//4>1,不管用了。置顶,地址为2,占[2];
short c;//4>2,按#pragma pack(2)对齐的话,前面一个字节要空着。即地址是4,占[4,5]
double d;//#pragma pack(4)对齐的话,#pragma pack(8),即为地址8,占[8~f];
}p;
画图理解:
|short---|char|----|short---|------|----|
|---------------double-------------------|
#pragma pack()//这是自定义对齐字节的结尾,即只有在#pragma pack(n)~#pragma pack()之间的代码才按照这种法则进行字节对齐。
再举个小例子:
#pragma pack(3)
struct s
{
short a;
char b;
}p;
#pragma pack()
画图理解:
|short---|
|char|---|
sizeof(p)=3?,不对,按前面的分析是=4.反对的童鞋可以自己在vs2012上试一试的。按照最长的short对齐,即#pragma pack(2),那么就是2+2;
有人会问,如果是这样的话:
#pragma pack(16)
struct s
{
double a;
char b;
double c;
}p;
#pragma pack()
怎么算sizeof(p).
如前面说的,16太大了,也使得这种自定义的字节无效了。即按#pragma pack(8)对齐,即sizeof(p)=24;而不是32。
再来一个例子:
#pragma pack(8)
struct s
{
int a;
char b;
int c;
}p;
#pragma pack()
结果是sizeof(p)=12;
再一个例子:
#pragma pack(4)
struct s
{
short a;
char b;
short c;
}p;
#pragma pack()
结果是:sizeof(p)=6;
以上都是说无效的情况,那么有效的时候呢?
有个比较特殊的情况,就是#pragma pack(1),会使得变量之间很紧凑,即计算这样处理的结构体的时候,计算sizeof,直接将各个变量长度相加即可。
又如,
#pragma pack(2)
struct s
{
double a;
char c;
short d;
}p;
#pragma pack()
结果是,sizeof(p)=12;一个有趣并且合理的现象,基本数据类型只有,1,2,4,8字节的。我们可以把double看成是4个2字节组成的,那么其他的一样分析,结果是:4x2+2+2=12.
差不多了,有错请大家指出,我们可以一起交流。第一次写博客,可能自己的表达能力不够好,请大家多多包涵。