内存对齐用法小结

今天偶然在贴吧里面看到有人问

struct A

{

  char a;

  double b;

};

 

使用C++的

sizeof(A);

结果为:16。

 

已经周折才把这个搞明白了。

 

下面我来说一下,看你能看的懂吗:

 

从大的方面来讲,今天我们说的这个内存边界对准,其实是为了提高内存访问速率,同时也提高了程序的可移植性。

我主要说明提高内存访问速率。

 

首先介绍一个事实,如果我们语言里面的内置数据类型所声明的对象没有按照其相应的内存边界对准,那么存储器很有可能要多次访存。

为什么?

假设有这么一种处理器,它只能访问8的倍数的内存地址(实际上现在的cpu基本都是这样,但不是8倍),而且每次写入或者读取都是8个字节。这么一来对我们的编程就造成影响了。假如有个double b;b的地址假设是0006,那么b所占据的地址段就0006-000D(16进制)。那么好了,这个cpu是不能在一次访问存储器就能取得这个数据的。它需要先访问0地址,取出0006-0007的数据,然后再访问0008-000D的数据。

 

但是要是我们本来就把double b;放在一个8倍的地址上,那么cpu就可以一次访问存储器就可以取得这个数据了。

所以结论是:内存地址对齐是很有必要的,速度提高了一倍哦。

 

移植性是因为有的cpu架构对某些类型只能够从特定形式的内存地址存取,否则就会出错。所以对于这类平台必须使用内存边界对准,而其他平台没有这类问题,所以按地址边界做的比较好,对一般机器可以,对别的机器也可以,所以提高了移植性。

 

接着我们在讲究竟是怎么对齐。我讲讲结构体的内存对齐问题:

假如:

struct A

{

    char a;

    short b;

    int b;

};

 

那么sizeof(A),究竟是多少呢?

答案是:8

 

按照一般计算式:1+2+4=7

 

但是内存边界对准有3条规则:

首先一般编译器自身就有一个默认的内存对齐模数(内存对齐模数就是以几倍地址对齐,模数就是几)是4或者8。VC应该是4

规则1:结构体内部数据的对齐,拿结构体的数据成员的大小(sizeof值)和默认对齐模数,谁小,就以谁为模数。

规则2:结构体本身的内存对齐,拿结构体内的数据成员的大小中最大的和默认对齐模数比较,谁小,就以谁为模数。

规则3:其实也是个定理,如果默认对齐模数比结构体中最大数据成员大是,那么默认对齐模数没用。

 

模数到底有什么用呢?看下面的实例:

 

用这个规则我们来看一下上面的struct A。假设默认对齐模式为4

struct A

{

    char a;//大小为1,因为1<4,所以以1为对齐模数,意思就是这个数据成员的地址只要是1的倍数就可以了,那么也就是任意地址。

               //那我们假设这个结构体的其实地址是0,那么a的地址是0。     即a=[0]

    short b;//大小为2,因为2<4,所以以2为对齐模数,意思就是这个数据成员的地址只要是2的倍数就可以了,那么也就是必须放在

                 //0,2,4,8为尾数的地址上,前面的a地址是0,大小是1,那么这样,后面的变量按理是在1地址上,但是刚才也说了必须要在

                //0,2,4,8为尾数的地址上,所以b必须放在2地址上。             即b=[2,3]

     int c;//大小为4,因为4=4,那么以4为对齐模数,所以c的地址必须尾数是4的倍数,正好可以放在地址4上。

               //                                                                                   即c=[4,5,6,7]

};

 

所以结构体A的数据成员的总大小是8。

但并没有完,虽然结果是8。

实际上编译器还要执行规则二。

那就是:用数据结构的最大数据成员大小MAX(char,short,int)=4,和默认的对齐模数4比较,选择较小的那个,所以以4为模数。

结构体的大小 =为了使 ( 数据结构成员的总大小 / 对齐模数 )圆整,而调节数据结构成员的大小后的值。

 

圆整的意思是: 3 / 4 结果是0.75,对结果圆整是1,调整3变成4,那么结果就是整数了。

 

所以结构体的大小=(8/4)圆整调后后的结果=8

 

但并未总是8.

 

如结构体A

{

    double a;

    char b;

}

 

数据成员大小是9

 

但结构体的大小=12。就是因为圆整。

 

但为什么要调整结构体的大小呢?(我想)

原因应该是就是满足对齐要求,时候后面变量分配的地址能满足对齐模数的要求。

如果结构体大小为9,那么后面结构体的变量开始地址从9开始,就很麻烦了。

时间: 2024-07-30 12:32:42

内存对齐用法小结的相关文章

C语言内存对齐详解

一.字节对齐基本概念     现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐. 对齐的作用和原因:各个硬件平台对存 储空间的处理上有很大的不同.一些平台对某些特定类型的数据只能从某些特定地址开始存取.比如有些架构的CPU在访问一个没有进行对齐的变量的时候会发生 错误,那么在这种架构下编程必须保

static用法小结

static用法小结 static关键字是C, C++中都存在的关键字, 它主要有三种使用方式, 其中前两种只指在C语言中使用, 第三种在C++中使用(C,C++中具体细微操作不尽相同, 本文以C++为准). (1)局部静态变量 (2)外部静态变量/函数 (3)静态数据成员/成员函数 下面就这三种使用方式及注意事项分别说明 一.局部静态变量 在C/C++中, 局部变量按照存储形式可分为三种auto, static, register (<C语言程序设计(第二版)>谭浩强, 第174-175页)

Java中的字符串用法小结_java

本文实例总结了Java中的字符串用法.分享给大家供大家参考.具体分析如下: 字符串的本质是char类型的数组,但在java中,所有用双引号""声明的字符串都是一个String类的对象.这也正体现了Java完全面向对象的语言特点. String 类 1.String类对象表示的是一个常量字符串.它是不可变长度的.也就是说,一旦创建了一个String类的实例,那么这个实例所表示的串是不可改变的.类似于 str = str + "Hello"; 这样的操作,实质上是将 s

C++中的string类的用法小结_javascript技巧

相信使用过MFC编程的朋友对CString这个类的印象应该非常深刻吧?的确,MFC中的CString类使用起来真的非常的方便好用.但是如果离开了MFC框架,还有没有这样使用起来非常方便的类呢?答案是肯定的.也许有人会说,即使不用MFC框架,也可以想办法使用MFC中的API,具体的操作方法在本文最后给出操作方法.其实,可能很多人很可能会忽略掉标准C++中string类的使用.标准C++中提供的string类得功能也是非常强大的,一般都能满足我们开发项目时使用.现将具体用法的一部分罗列如下,只起一个

C语言内存对齐实例详解_C 语言

本文详细讲述了C语言程序设计中内存对其的概念与用法.分享给大家供大家参考之用.具体如下: 一.字节对齐基本概念 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐. 对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同.一些平台对某些特定类型的数据只能从某些特定地址开始存取.比如有些架构的C

详解PHP中cookie和session的区别及cookie和session用法小结

具体来说 cookie 是保存在"客户端"的,而session是保存在"服务端"的 cookie 是通过扩展http协议实现的 cookie 主要包括 :名字,值,过期时间,路径和域: 如果cookie不设置生命周期,则以浏览器关闭而关闭,这种cookie一般存储在内存而不是硬盘上.若设置了生命周期则相反,不随浏览器的关闭而消失,这些cookie仍然有效直到超过设定的过 期 时间. session 一种类似散列表的形式保存信息, 当程序需要为某个客户端的请求创建一个

内存对齐原则

内存对齐,一般针对结构体或者是类 系统默认内存对其字数是4 可以使用   #pragma  pack(n)   来设置对齐字数,1,2,8.   对齐原则:(以4字节为例) 对于大于等于4字节的成员起始位置应该是4的整数倍,对于等于2字节的成员,起始位置应该是2的整数倍,对于1字节的成员,可以在任意位置,但是成员顺序应该和定义顺序一致,不能改变.总结构体的大小应该是4的倍数.    

c/c++中内存对齐详解

一,什么是内存对齐?内存对齐用来做什么? 所谓内存对齐,是为了让内存存取更有效率而采用的一种编译阶段优化内存存取的手段. 比如对于int x;(这里假设sizeof(int)==4),因为cpu对内存的读取操作是对齐的,如果x的地址不是4的倍数,那么读取这个x,需要读取两次共8个字节,然后还要将其拼接成一个int,这比存取对齐过的x要麻烦很多. 二,怎么算内存对齐大小(理论)? 对于简单类型,如int,char,float等,其对齐大小为其本身大小,即align(int) == sizeof(i

深入理解C语言内存对齐

 这篇文章主要介绍了C语言内存对齐,有需要的朋友可以参考一下 一.内存对齐的初步讲解   内存对齐可以用一句话来概括:   "数据项只能存储在地址是数据项大小的整数倍的内存位置上"   例如int类型占用4个字节,地址只能在0,4,8等位置上.   例1:   代码如下: #include <stdio.h> struct xx{         char b;         int a;         int c;         char d; };   int m