打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
简要记录sizeof和内存对齐
userphoto

2012.03.13

关注
今天有人在某QQ群中问下面这个结构体有多大:
#pragma pack(4)struct STV{	char a;	short int b;	char c;};

当时我第一反应是12,不过又总觉得有点不对劲,还是写了段代码测试下,发现结果居然是6.

嗯?6,难道编译器没看到这句话么:#pragma pack(4)?

但是当我把结构体的定义修改为

#pragma pack(1)struct STV{	char a;	short int b;	char c;};

后,结果又变成了4,那么#pragma pack是在起作用的。然后又试着改为#pragma pack(8)和#pragma pack(16),结果还是6.

心中大概有点明白为什么了。

google之,原来对于#pragma pack的处理方式是这样进行的:

当结构体中最长宽度的数据成员的宽度小于 n 时,按该成员宽度对齐;
当最长宽度的数据成员的宽度大于或等于 n 时,按 n 对齐。

结构体STV中成员宽度最大为2,所以当n=4,8,16的时候还是按照宽度2来对齐的。

–EOF
 
 
 
 
 
    本来,一般是不自己计算sizeof的,知道内存对齐会对sizeof有影响,所以从来不手算,而是代码里写上sizeof。今天又看到http://blog.vckbase.com/smileonce/archive/2005/08/08/10658.html,翻来了http://blog.vckbase.com/billdavid/archive/2004/06/23/509.html ,自己想想还是也记录一下,万一以后自己真的也要计算sizeof,忘了,还能有个提示,也给不是很明白的朋友一个参考。
struct sample1
{
    char a;        /// sizeof(char) = 1
    double b;    /// sizeof(double) = 8
};
///default(  缺省#pragam pack(8) ——VC6和VC71,其它编译器,个人未知 )
    ///1+8 = 9 —> 16(  8 < 9 < 16  )

#pragma pack( 4 )
    ///1+8 = 9 —> 12(  8 < 9 < 12  )

#pragma pack( 2 )
    ///1+8 = 9 —> 10(  8 < 9 < 10  )

#pragma pack( 1 )
    ///1+8 = 9 —> 9

#pragma pack( 16 )
    ///1+8 = 9 —> 16(  16—>8 ---- 8 < 9 < 16  )

struct sample2
{
    char a;     ///1
    int b;        ///4
};
#pragma pack( 8 )
    /// 1 + 4  = 5 —> 8(  8 —> 4  )

#pragma pack( 16 )
    /// 1 + 4 = 5 —> 8( 16 —> 4  )

    说明:#pragma pack告诉编译器进行内存边界对齐,一般都是采用编译器的设置对整个项目采用同一对齐方案,而且通常为缺省8字节对齐。



/////////////////////////////////以下内容于 2005-12-10 添加/////////////////////////////////


    今天又看到以前测试的一段代码,突然不明白了起来,又稍写了几个测试。
struct sample3
{
    char a;  ///1
    int b;    ///4
    char c;  ///1
};
///default                  ///12
#pragma pack( 4 )   ///12
#pragma pack( 2 )   ///08
#pragma pack( 1 )   ///06
#pragma pack( 16 ) ///12

    原来,其实编译器,根据对齐指示的对齐字节和最大成员的字节,对每个成员进行了对齐:编译器会取对齐指示和最大成员字节中较小的一个用于补齐其它成员。那么,上面的sample1/2/3也就都在情理之中了。为了证实这点,我们还再看一个例子:
struct sample4
{
    char a;      ///1
    int b;         ///4
    double c;  ///8
    char d;      ///1
};
///default:                ///8+8+8+8 = 32
#pragma pack( 4 )   ///4+4+8+4 = 20
#pragma pack( 2 )   ///2+4+8+2 = 16
#pragma pack( 1 )   ///1+4+8+1 = 14
#pragma pack( 16 ) ///8+8+8+8 = 32
而实际上,编译器给出的值是:24、20、16、14、24
那么说明我错了。注意一下,我发现char a,int b加起来也才5<8,难到编译器进行了联合对齐?
struct sample5
{
    char a;      ///1
    double c;  ///8
    int b;         ///4
    char d;      ///1
};
编译器给出结果:24、20、16、14、24

    这用联合对齐的解释正好符合,我又试验了不同的数据,发现这个结论并不太准确确。于是,我输出了每一个对象成员地址进行分析。由于试验数据量很大,这里就不列出了。

最后得到了以下结论:
    1. 成员的对齐是按声明顺序进行的;
    2. 对齐值由编译指示和最大成员两者较小的值决定;
    3. 未对齐到对齐值的成员一起形成块对齐(联合对齐);
    4. 上一个(下一个)对齐采用自己较大则不变,自己较小则填充自己对齐到上一个(下一个)大小;
    5. 每成员对齐:如果前面已对齐到对齐值,下一个对齐自己。如果前面未对齐到对齐值,如果加上下一个成员不大于对齐值,下一个对齐自己,否则填充自己块对齐到对齐值。
    6. 最后还未对齐到对齐值的,填充空间块对齐到对齐值。

从这些结论,可以得到:
    1. 以上的对齐原则其实是尽量整齐排列、尽量节省内存。
    2. 声明成员应该尽量避免不同类型错杂开来,最好采用从小到大或者从大到小的顺序(错开后,会因为上对齐和下对齐而增加填充开销)。
    3. 编译器缺省采用8字节对齐主要是因为最大基本类型为8自己(以前自己不明白,在论坛提过问,后来,以为是SSE指令的原因)。
    4. 手算sizeof是没有必要的,负责的(可以先对齐出对齐块,用块数乘对齐值)。

posted on 2005-08-09 21:14 终于有了间茅草棚 阅读(14941) 评论(10)  编辑 收藏

评论

# re: 简要记录sizeof和内存对齐

反正我是从来都是按照16字节对齐的,不够的话使用 BYTE m_reserved[n];来凑齐
例如:
struct sample1
{
    char a;
    double b; 
    BYTE m_reserved[7];
};
2005-08-09 23:50 | hengai

# re: 简要记录sizeof和内存对齐

只是描述一下怎么算。以及,告诉初学者,有填充。
这样,在处理时有所优化,比如:发送网络数据时,发整个块就不是很明智。
2005-08-10 22:03 | 清风雨

# re: 简要记录sizeof和内存对齐

怎么和panic说的不太一样??

http://blog.vckbase.com/panic/archive/2005/04/02/4340.aspx
2005-08-11 08:56 | yuxuan

# re:yuxuan

是一样的。 仔细研究一下就明白了。
2005-08-11 11:28 | 清风雨

# re: 简要记录sizeof和内存对齐

不错,很详细,我也是刚知道不久的,惭愧惭愧。。。
2005-12-17 18:19 | edog

# 简要记录sizeof和内存对齐 [TrackBack]

http://blog.vckbase.com/zhangjw_cn/archive/2005/08/09/10701.html
uvbs引用了该文章,地址:http://blog.csdn.net/UVBS/archive/2006/03/21/630971.aspx
2006-03-21 11:57 | uvbs

# 一些关于sizeof的例子[TrackBack]

转自:http://zhengrongyang.spaces.live.com/blog/对几组sizeof信息的分析对几组sizeof信息的分析 对于很多C 新手而言,对象或变量的sizeof信息总是让人捉摸不透,以下程序列举了几个典型的sizeof信息,希望能解答大家在使用sizeof时的疑问。
fengsanshao引用了该文章,地址:http://blog.csdn.net/fengsanshao/archive/2007/03/18/1533036.aspx
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
结构体(含位域)的sizeof
也谈内存对齐 :: Tony Bai
亲历多家名企C语言面试题
C语言结构体对齐问题
简要讲述C/C++中的操作符sizeof()
结构体对齐问题.
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服