大家都知道,C++空类的内存大小为1字节,为了保证其对象拥有彼此独立的内存地址。非空类的大小与类中非静态成员变量和虚函数表的多少有关。

而值得注意的是,类中非静态成员变量的大小与编译器内存对齐的设置有关。

成员变量在类中的内存存储并不一定是连续的。它是按照编译器的设置,按照内存块来存储的,这个内存块大小的取值,就是内存对齐。

 一、引入问题。

#include<iostream>
using namespace std;
class test {
private : char c='';//1byte
int i;//4byte
short s=;//2byte
}; int main(){
cout << sizeof(test) << endl;
return ;
}

输出:12

class test2 {
private:
int i;//4byte
char c = '';//1byte
short s = ;//2byte
}; int main(){
cout << sizeof(test2) << endl;
return ;
}

输出:8

我们可以看到。类test和test2的成员变量完全一样,只是定义顺序不一样,却造成了2个类占用内存大小不一样。而这就是编译器内存对齐的缘故。

二、规则

1、第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。

2、在数据成员完成各自对齐之后,类(结构或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。

  很明显#pragma pack(n)作为一个预编译指令用来设置多少个字节对齐的。值得注意的是,n的缺省数值是按照编译器自身设置,一般为8,合法的数值分别是1、2、4、8、16。

  即编译器只会按照1、2、4、8、16的方式分割内存。若n为其他值,是无效的。

三、问题分析

(1)对于类test的内存空间是这样的:

内存分配过程:

1、char和编译器默认的内存缺省分割大小比较,char比较小,分配一个字节给它。

2、int和编译器默认的内存缺省分割大小比较,int比较小,占4字节。只能空3个字节,重新分配4个字节。

3、short和编译器默认的内存缺省分割大小比较,short比较小,占2个字节,分配2个字节给它。

4、对齐结束类本身也要对齐,所以最后空余的2个字节也被test占用。

(2)对于类test2的内存空间是这样的:

1、int和编译器默认的内存缺省分割大小比较,int比较小,占4字节。分配4个字节给int。

2、char和编译器默认的内存缺省分割大小比较,char比较小,分配一个字节给它。

3、short和编译器默认的内存缺省分割大小比较,short比较小,此时前面的char分配完毕还余下3个字节,足够short的2个字节存储,所以short紧挨着。分配2个字节给short。

4、对齐结束类本身也要对齐,所以最后空余的1个字节也被test占用。

(3)使用#pragma pack(n)

#include<iostream>
using namespace std;
#pragma pack(1)//设定为 1 字节对齐
class test {
private : char c='';//1byte
int i;//4byte
short s=;//2byte
}; class test2 {
private:
int i;//4byte
char c = '';//1byte
short s = ;//2byte
};
int main(){
cout << sizeof(test) << endl;
cout << sizeof(test2) << endl;
return ;
}

输出:

可以看到,当我们把编译器的内存分割大小设置为1后,类中所有的成员变量都紧密的连续分布。

至此,C++内存对齐总结已经差不多了。想要更多了解C++对象内存分配推荐陈浩的2篇文章:

http://blog.csdn.net/haoel/article/details/3081328

和http://blog.csdn.net/haoel/article/details/1948051

陈浩大神写的太透彻了。

参考:http://www.cppblog.com/snailcong/archive/2009/03/16/76705.html

http://www.jb51.net/article/45406.htm

最新文章

  1. 一年之计在于春,2015开篇:PDF.NET SOD Ver 5.1完全开源
  2. 《Entity Framework 6 Recipes》中文翻译系列 (30) ------ 第六章 继承与建模高级应用之多对多关联
  3. WPF 自定义雷达图
  4. effective java —— 终结方法守卫者
  5. C#中DateTime.Now.ToString()
  6. 使用 archetype插件创建maven目录结构
  7. python ljust,rjust,center,zfill对齐使用方法
  8. MVC Area Usage
  9. assert的用处
  10. leetcode 27
  11. 简单图片banner轮播
  12. JavaScript 的setAttribute兼容性解决
  13. 有利于SEO的DIV+CSS规范小结
  14. Selenium模拟JQuery滑动解锁
  15. (转)从史上八大MySQL宕机事故中学到的经验
  16. navicat导入.sql文件
  17. springmvc 项目完整示例04 整合mybatis mybatis所需要的jar包 mybatis配置文件 sql语句 mybatis应用
  18. svn各种表示含义及解决
  19. 将caj文件转化为pdf文件进行全文下载脚本(ubuntu下亲测有用)
  20. 一个可用来记录Isilon各个节点的CPU,网络,磁盘性能的命令

热门文章

  1. C语言 &#183; 矩形面积交
  2. Java基础Map接口+Collections
  3. 菜鸟学Struts2——零配置(Convention )
  4. android 使用Tabhost 发生could not create tab content because could not find view with id 错误
  5. 卡片抽奖插件 CardShow
  6. 如何定位Oracle数据库被锁阻塞会话的根源
  7. Java FtpClient 实现文件上传服务
  8. setCapture、releasCapture 浅析
  9. interpreter(解释器模式)
  10. PHP 设计模式概述