#pragma pack(n)的用法

在看《程序员面试宝典(第四版)》中,第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.

差不多了,有错请大家指出,我们可以一起交流。第一次写博客,可能自己的表达能力不够好,请大家多多包涵。









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值