数据对齐,是指数据所在的内存地址必须是该数据长度的整数倍。DWORD数据的内存起始地址能被4除尽,WORD数据的内存起始地址能被2除尽。X86 CPU能直接访问对齐的数据,当它试图访问一个未对齐的数据时,会在内部进行一系列的调整。这些调整对于程序员来说是透明的,但是会降低运行速度,所以编译器在编译程序时会尽量保证数据对齐。

不同的编译器内存对齐的方式不同。

一个小例子:在32位的机器上,数据是以4字节为对齐单位,这两个类的输出结果为什么不同?(VS2008)

  1. #include <iostream>
  2. using namespace std;
  3. class B
  4. {
  5. private:
  6. bool m_bTemp;
  7. int m_nTemp;
  8. bool m_bTemp2;
  9. };
  10. class C
  11. {
  12. private:
  13. int m_nTemp;
  14. bool m_bTemp;
  15. bool m_bTemp2;
  16. };
  17. int _tmain(int argc, _TCHAR* argv[])
  18. {
  19. cout<<sizeof(B)<<endl;
  20. cout<<sizeof(C)<<endl;
  21. system("pause");
  22. return 0;
  23. }

答案是:3*4=12,2*4=8

分析:在访问内存时,如果地址按4字节对齐,则访问的效率会高很多。

考虑到性能方面,编译器会对结构进行对齐处理,考虑下面的结构:

struct aStruct

{

char cValue;

int iValue;

};

直观地讲,这个结构的尺寸是sizeof(char)+sizeof(int)=6,但是在实际编译下, 这个结构尺寸默认是8,因为第二个域iValue会被对齐到第4个字节。

注意:字节对齐是编译时决定的,一旦决定则不会再改变,因此即使有对齐的因素存在,也不会出现一个结构在运行时尺寸发生变化的情况。

在本题中:第一种类的数据对齐是下面的情况:

bool ---- ---- ----

------- int ---------

bool ----- ---- ----

第二种类的数据对齐是下面的情况:

------- int ----------

bool bool ---------

所以类的大小分别3*4和2*4

一般在VC++中加上#pragma pack(n)设置内存对齐。

我们可以利用#pragma pack()来改变编译器的默认对齐方式。

#pragma pack(n)   //编译器将按照n字节对齐

#pragma pack()     //编译器将取消自定义字节对齐方式

在#pragma pack(n)和#pragma pack()之间的代码按n字节对齐。

但是成员对齐有一个重要的条件,即每个成员按照自己的对齐方式对齐;也就是说虽然指定了按n字节对齐,但并不是所有的成员都以n字节对齐。

对齐的规则是:每个成员按其类型的对齐参数(通常是这个类型的大小)和指定对齐参数(这里是n字节)中较小的一个对齐,即min(n,sizeof(item)),并且结构的长度必须为所用过的所有对齐参数的整数倍,不够就补空字节。

  1. #pragma pack(8)
  2. struct TestStruct4
  3. {
  4. char a;
  5. long b;
  6. };
  7. struct TestStruct5
  8. {
  9. char c;
  10. TestStruct4 d;
  11. long long e;
  12. };
  13. int _tmain(int argc, _TCHAR* argv[])
  14. {
  15. cout<<sizeof(TestStruct4)<<endl;
  16. cout<<sizeof(TestStruct5)<<endl;
  17. system("pause");
  18. return 0;
  19. }

运行结果为:8,24

分析:

TestStruct4 中,成员a是1字节,默认按照1字节对齐,指定对齐参数是8,这两个值中取1,a按1字节对齐;

成员b是4字节,默认是按4字节对齐,这时就按4字节对齐,所以sizeof(TestStruct4)应该是8.

TestStruct5 中,c和TestStruct4中的a一样,按1字节对齐;而d是个结构,它是8字节,对于结构来说,它的默认对齐方式就是其所有成员使用的对齐参数中最大的一个,TestStruct4就是4,所以成员d就按照4字节对齐。成员e是8字节,它是默认的8字节对齐,和指定的一样,所以它对齐到8自己的边界上,这时,已经使用了12字节了,所以又添加了4字节的空间,从第16字节开始放置成员e。这时长度为24,已经可以被8整除(成员e按8字节对齐)。这样一共使用了24字节。

内存布局图如下:

TestStruct4 的内存布局:

a      b

1***   1111

TestStruct5 的内存布局:

c     d.a      d.b                e

1***   1***     1111    ****    11111111

注意3点:

(1)每个成员按照自己的方式对齐,并能最小化长度

(2)复杂类型(如结构)的默认对齐方式是它最长的成员的对齐方式,这样在成员是复杂类型时,可以最小化长度。

(3)对齐后的长度必须是成员中最大的对齐参数的整数倍,这样在处理数组时可以保证每一项都边界对齐。

补充:对于数组,比如说char a[3],它的对齐方式和分别写3个char是一样的,也就是说它还是按1字节对齐;如果写成typedef char Arrary3[3],Arrary3这种类型的对齐方式还是按1字节对齐,而不是按它的长度。

但是不论类型是什么,对齐的边界一定是1、2、4、8、16、32、64......中的一个。

下面来说下大端模式和小端模式

大端模式:认为第一个字节是最高位字节,也就说按照从低地址到高地址的顺序存放数据的高位字节到低位字节。

小端模式:认为第一个字节是最低位字节,也就是说按照从低地址到高地址的顺序存放数据的低位字节到高位字节。

假设从内存地址0x0000开始有以下数据:

内存地址:0x0000    0x0001    0x0002     0x0003

对应数据:0x12       0x34      0x56       0x78

如果我们去读取一个地址为0x0000的4字节变量

若字节序位为小端模式,读出为:0x78563412

若字节序位为大端模式,读出为:0x12345678

一般来说:X86系列的CPU都是小端字节序,powerPC通常是大端字节序。

  1. int _tmain(int argc, _TCHAR* argv[])
  2. {
  3. char *sz = "0123456789";
  4. int *p = (int *)sz;
  5. cout<<hex<<*++p<<endl;
  6. }

运行结果为:37363534

分析:这里是小端字节序

地址从0x0000开始,那么sz在内存中的存储为:

内存地址:     0x00  0x01  0x02   0x03   0x04  0x05  0x06   0x07   0x08  0x09

对应的值:      0      1     2      3      4     5     6      7     8      9

对应的值:      48     49    50     51     52    53    54     55    56     57

对应的16进制:0x30   0x31  0x32   0x33   0x34  0x35  0x36   0x37  0x38   0x39

sz                         ++p

所以读取为:0x37363534

最新文章

  1. Tomcat启动后,从spring容器中获取Bean和ServletContext
  2. PHP处理一个5G文件,使用内存512M的,数据为整形,从大到小排序,优化排序算法
  3. cookie 的创建 得到 删除
  4. Php 安装 curl
  5. [Unity] 精灵动画制作中需要注意的一些问题
  6. Create Hierarchical Tree To Control Records In Oracle Forms
  7. mongodb 查询使用
  8. winfrom之动态控件生成以及保存动态空间的数据
  9. Java String.split()注意点
  10. 【LeetCode练习题】Maximum Depth of Binary Tree
  11. Python学习入门基础教程(learning Python)--3.3.1 Python下的布尔表达式
  12. WordPress 4.8 安装配置教程 (基于 centos 7.3, php 7.0, mysql 5.7.19, nginx 1.12.1)
  13. HTML学习笔记 CSS文本及字体及连接及列表(a标签使用及缩进) 案例 第七节 (原创)参考使用表
  14. Suricata默认规则集相关
  15. python3的socket使用
  16. Unity3D手机斗地主游戏开发实战(02)_叫地主功能实现
  17. Codeforces 444 C - DZY Loves Colors
  18. JSP指令(page include taglib)
  19. array_multisort—对多个数组或多维数组进行排序
  20. uva1494 最小生成树--例题

热门文章

  1. was cached in the local repository, resolution will not be reattempted until the update interval of localhost-repository has elapsed or updates are forced
  2. ipv4组播预留地址
  3. MUI---IOS切换到后台继续播放音乐
  4. pandas生成时间列表(某段连续时间或者固定间隔时间段)
  5. 9.6Django
  6. vs code 搭建flutter运行环境(mac)
  7. 小程序中的block
  8. Memcached 简单利用和简单了解(Mac的安装和使用)
  9. CH6101 最优贸易【最短路】
  10. python中super的使用方法