在最近的项目中,我们涉及到了“内存对齐”技术。对于大部分程序员来说,“内存对齐”对他们来说都应该是“透明的”。“内存对齐”应该是编译器的“管辖范围”。编译器为程序中的每个“数据单元”安排在适当的位置上。但是C语言的一个特点就是太灵活,太强大,它允许你干预“内存对齐”。如果你想了解更加底层的秘密,“内存对齐”对你就不应该再透明了。

一、内存对齐的原因 大部分的参考资料都是如是说的: 1、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。 2、性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

二、对齐规则 每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。程序员可以通过预编译命令#pragma  pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。

规则: 1、数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragma  pack指定的数值和这个数据成员自身长度中,比较小的那个进行。 2、结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma  pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。 3、结合1、2颗推断:当#pragma  pack的n值等于或超过所有数据成员长度的时候,这个n值的大小将不产生任何效果。

三、试验 我们通过一系列例子的详细说明来证明这个规则吧! 我试验用的编译器包括GCC 3.4.2和VC6.0的C编译器,平台为Windows  XP + Sp2。

我们将用典型的struct对齐来说明。首先我们定义一个struct: #pragma pack(n) /* n = 1, 2, 4, 8, 16  */ struct test_t {  int a;  char b;  short c;  char  d; }; #pragma  pack(n) 首先我们首先确认在试验平台上的各个类型的size,经验证两个编译器的输出均为: sizeof(char) =  1 sizeof(short) = 2 sizeof(int) = 4

我们的试验过程如下:通过#pragma pack(n)改变“对齐系数”,然后察看sizeof(struct test_t)的值。

1、1字节对齐(#pragma pack(1)) 输出结果:sizeof(struct test_t) = 8  [两个编译器输出一致] 分析过程: 1) 成员数据对齐 #pragma pack(1) struct test_t {  int  a;  /* 长度4 < 1 按1对齐;起始offset=0 0%1=0;存放位置区间[0,3] */  char b;  /* 长度1 = 1  按1对齐;起始offset=4 4%1=0;存放位置区间[4] */  short c; /* 长度2 > 1 按1对齐;起始offset=5  5%1=0;存放位置区间[5,6] */  char d;  /* 长度1 = 1 按1对齐;起始offset=7 7%1=0;存放位置区间[7]  */ }; #pragma pack() 成员总大小=8

2) 整体对齐 整体对齐系数 = min((max(int,short,char), 1) = 1 整体大小(size)=$(成员总大小) 按  $(整体对齐系数) 圆整 = 8 /* 8%1=0 */ [注1]

2、2字节对齐(#pragma pack(2)) 输出结果:sizeof(struct test_t) = 10  [两个编译器输出一致] 分析过程: 1) 成员数据对齐 #pragma pack(2) struct test_t {  int  a;  /* 长度4 > 2 按2对齐;起始offset=0 0%2=0;存放位置区间[0,3] */  char b;  /* 长度1 <  2 按1对齐;起始offset=4 4%1=0;存放位置区间[4] */  short c; /* 长度2 = 2 按2对齐;起始offset=6  6%2=0;存放位置区间[6,7] */  char d;  /* 长度1 < 2 按1对齐;起始offset=8 8%1=0;存放位置区间[8]  */ }; #pragma pack() 成员总大小=9

2) 整体对齐 整体对齐系数 = min((max(int,short,char), 2) = 2 整体大小(size)=$(成员总大小) 按  $(整体对齐系数) 圆整 = 10 /* 10%2=0 */

3、4字节对齐(#pragma pack(4)) 输出结果:sizeof(struct test_t) = 12  [两个编译器输出一致] 分析过程: 1) 成员数据对齐 #pragma pack(4) struct test_t {  int  a;  /* 长度4 = 4 按4对齐;起始offset=0 0%4=0;存放位置区间[0,3] */  char b;  /* 长度1 < 4  按1对齐;起始offset=4 4%1=0;存放位置区间[4] */  short c; /* 长度2 < 4 按2对齐;起始offset=6  6%2=0;存放位置区间[6,7] */  char d;  /* 长度1 < 4 按1对齐;起始offset=8 8%1=0;存放位置区间[8]  */ }; #pragma pack() 成员总大小=9

2) 整体对齐 整体对齐系数 = min((max(int,short,char), 4) = 4 整体大小(size)=$(成员总大小) 按  $(整体对齐系数) 圆整 = 12 /* 12%4=0 */

4、8字节对齐(#pragma pack(8)) 输出结果:sizeof(struct test_t) = 12  [两个编译器输出一致] 分析过程: 1) 成员数据对齐 #pragma pack(8) struct test_t {  int  a;  /* 长度4 < 8 按4对齐;起始offset=0 0%4=0;存放位置区间[0,3] */  char b;  /* 长度1 <  8 按1对齐;起始offset=4 4%1=0;存放位置区间[4] */  short c; /* 长度2 < 8 按2对齐;起始offset=6  6%2=0;存放位置区间[6,7] */  char d;  /* 长度1 < 8 按1对齐;起始offset=8 8%1=0;存放位置区间[8]  */ }; #pragma pack() 成员总大小=9

2) 整体对齐 整体对齐系数 = min((max(int,short,char), 8) = 4 整体大小(size)=$(成员总大小) 按  $(整体对齐系数) 圆整 = 12 /* 12%4=0 */

5、16字节对齐(#pragma pack(16)) 输出结果:sizeof(struct test_t) = 12  [两个编译器输出一致] 分析过程: 1) 成员数据对齐 #pragma pack(16) struct test_t {  int  a;  /* 长度4 < 16 按4对齐;起始offset=0 0%4=0;存放位置区间[0,3] */  char b;  /* 长度1 <  16 按1对齐;起始offset=4 4%1=0;存放位置区间[4] */  short c; /* 长度2 < 16  按2对齐;起始offset=6 6%2=0;存放位置区间[6,7] */  char d;  /* 长度1 < 16 按1对齐;起始offset=8  8%1=0;存放位置区间[8] */ }; #pragma pack() 成员总大小=9

2) 整体对齐 整体对齐系数 = min((max(int,short,char), 16) = 4 整体大小(size)=$(成员总大小)  按 $(整体对齐系数) 圆整 = 12 /* 12%4=0 */

四、结论 8字节和16字节对齐试验证明了“规则”的第3点:“当#pragma  pack的n值等于或超过所有数据成员长度的时候,这个n值的大小将不产生任何效果”。另外内存对齐是个很复杂的东西,上面所说的在有些时候也可能不正确。呵呵^_^

[注1] 什么是“圆整”? 举例说明:如上面的8字节对齐中的“整体对齐”,整体大小=9 按 4 圆整 =  12 圆整的过程:从9开始每次加一,看是否能被4整除,这里9,10,11均不能被4整除,到12时可以,则圆整结束。

c语言中内存对齐问题的更多相关文章

  1. C语言中内存对齐规则讨论(struct)

    C语言中内存对齐规则讨论(struct) 对齐: 现代计算机中内存空间都是按着byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地 ...

  2. C语言中内存对齐方式

    一.什么是对齐,以及为什么要对齐: 1. 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问, ...

  3. C语言中内存对齐与结构体

    结构体 结构体是一种新的数据类型,对C语言的数据类型进行了极大的扩充. struct STU{ int age; char name[15]; }; struct STU a; //结构体实例 str ...

  4. C语言中内存对齐

    今天一考研同学问我一个问题,一个结构体有一个int类型成员和一个char类型成员,问我这个结构体类型占多少个字节,我直接编个程序给他看结果.这个结构体占八个字节,咦,当时我蛮纳闷的,一个int类型四个 ...

  5. C语言中内存分配 (转)

    在任何程序设计环境及语言中,内存管理都十分重要.在目前的计算机系统或嵌入式系统中,内存资源仍然是有限的.因此在程序设计中,有效地管理内存资源是程序员首先考虑的问题. 第1节主要介绍内存管理基本概念,重 ...

  6. 【转】C语言中内存分配

    原文:C语言中内存分配 在任何程序设计环境及语言中,内存管理都十分重要.在目前的计算机系统或嵌入式系统中,内存资源仍然是有限的.因此在程序设计中,有效地管理内存资源是程序员首先考虑的问题. 第1节主要 ...

  7. C语言中内存分配问题:

    推荐: C语言中内存分配 Linux size命令和C程序的存储空间布局 本大神感觉,上面的链接的内容,已经很好的说明了: 总结一下: 对于一个可执行文件,在linux下可以使用 size命令列出目标 ...

  8. C语言中内存分配

     C语言中内存分配   在任何程序设计环境及语言中,内存管理都十分重要.在目前的计算机系统或嵌入式系统中,内存资源仍然是有限的.因此在程序设计中,有效地管理内存资源是程序员首先考虑的问题. 第1节主要 ...

  9. C语言中内存的申请函数

    C语言跟内存申请相关的函数主要有 alloca,calloc,malloc,free,realloc,sbrk等. alloca是向栈申请内存,因此无需释放. malloc分配的内存是位于堆中的,并且 ...

随机推荐

  1. 关于UIButton中的ContentEdgeInsets的深入研究

    UIButton的contentEdgeInsets属性的深入研究 由于用UIButton这个属性做过一些东西,但是对它的规律始终不太了解,虽然苹果官方文档的解释大体上可以理解为,这个属性设置的是内边 ...

  2. Java宝典(三)

    --说说ArrayList,Vector,LinkedList的存储性能和特性. --ArrayList和Vector都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,他们都 ...

  3. 最小费用最大流模板 poj 2159 模板水题

    Going Home Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 15944   Accepted: 8167 Descr ...

  4. phpcms加载系统类与加载应用类之区别详解

    <?php 1. 加载系统类方法load_sys_class($classname, $path = ''", $initialize = 1)系统类文件所在的文件路径:/phpcms ...

  5. mysql 编码设置

    (windows下) 打开C:\Program Files\MySQL\MySQL Server 5.0\my.ini (ubuntu下) 打开 /etc/mysql/my.cnf 在[client] ...

  6. ZooKeeper的学习与应用

    近期大概学习了一下ZooKeeper,本身并没有深入.LGG尝试着在虚拟机里面搭了平台,看了看一些教材,从网上到处看别人的博文并引用之,还请各位大牛们谅解我的剽窃.现总结例如以下. 1. ZooKee ...

  7. java遍历泛型的方法

    一.List遍历 Java中List遍历有三种方法来遍历泛型,主要为: 1.for循环遍历 2.iterator遍历 3.foreach遍历 package com.gmail.lsgjzhuwei; ...

  8. Flashback Query(函数示例)

    Flashback Query 函数,存储过程,包,触发器等对象Flashback Drop 可以闪回与表相关联的对象, 如果是其他的对象,比如function,procedure,trigger等. ...

  9. document.write 存在几个问题?应该注意

    document.write (henceforth DW) does not work in XHTML XHTML 不支持 DW executed after the page has finis ...

  10. 自己对WSO2 ESB 见解

    这周没想到要更新什么内容,就把我最近工作接触的WSO2 ESB简单介绍下吧.     前提: 一切文档,知识都要与官方文档为准. WSO2 ESB: http://wso2.com/products/ ...