C++ 内存对齐

注:本文代码测试环境为win7 X64 cpu, 编译器为gcc4.7.1 和 vs2010

 

内存对齐是编译器为了便于CPU快速访问而采用的一项技术

我们先从一个例子开始,对下面的类(或者结构体)

class node

{

char c;

int i;

short s;

}no;

sizeof(no)的值是多少呢,如果你的回答是7(1+4+2),那么你应该认真阅读下面的内容。可以在编译器上试试,输出的结果是12,这就是内存对齐的结果。

 

为什么要进行内存对齐呢?

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

编译器一般按照几个字节对齐呢?本文中两个编译器默认按照类中最大类型长度来对齐,我么也可以使用语句#pragma pack(i)(i = 1,2,4,8,16)来设置对齐字节数目,vs还可以在项目属性-配置属性-c/c++-代码生成-结构成员对齐设置。

 

对齐规则如下:

  1. 如果设置了内存对齐为 i 字节,类中最大成员对齐字节数为j,那么整体对齐字节n = min(i, j)  (某个成员的对齐字节数定义:如果该成员是c++自带类型如int、char、double等,那么其对齐字节数=该类型在内存中所占的字节数;如果该成员是自定义类型如某个class或者struct,那个它的对齐字节数 = 该类型内最大的成员对齐字节数《详见实例4》)
  2. 每个成员对齐规则:类中第一个数据成员放在offset为0的位置;对于其他的数据成员(假设该数据成员对齐字节数为k),他们放置的起始位置offset应该是 min(k, n) 的整数倍
  3. 整体对齐规则:最后整个类的大小应该是n的整数倍
  4. 当设置的对齐字节数大于类中最大成员对齐字节数时,这个设置实际上不产生任何效果(实例2);当设置对齐字节数为1时,类的大小就是简单的把所有成员大小相加

我们通过以下几个实例来分析

实例1:(没有指定对齐字节,则n = 最大成员(int i)的大小4)

class node

{

char c;   //放在位置0,位置区间[0]

int i;      //4 = n, 那么放置起始位置应该是4的倍数,即4,位置区间为[4~7]

short s; //2 < n,那么放置起始位置应该是2的倍数,即8,位置区间为[8~9]

}

此时成员共占用[0~9]10个字节,还要整体对齐,大小应该是4的倍数,即12

 

实例2:(假设指定对齐字节为8,那么n = min(8,4) = 4)

class node

{

int i; //放在位置0,位置区间[0~3]

char c; //1 < n, 那么放置起始位置应该是1的倍数,即4,位置区间为[4]

short s; //2 < n,那么放置起始位置应该是2的倍数,即6,位置区间为[6~7]

}

成员共占据[0~7]8个字节,刚好是4的倍数,因此大小是8

 

实例3:(假设指定对齐字节是2,则n = min(2,4) = 2)

class node

{

char c; //放在位置0,位置区间[0]

int i; //4 > n, 那么放置起始位置应该是2的倍数,即2,位置区间为[2~5]

short s; //2 = n,那么放置起始位置应该是2的倍数,即6,位置区间为[6~7]

}

此时成员共占用[0~7]8个字节,刚好是4的倍数,因此大小是8

 

实例4:(按照默认设置)

class temp 

    char c; 
    int i; 
    short s1; 
};

由实例1可知,默认对齐情况下,temp的大小是12,temp的对齐字节数是:三个成员取最大的,即为4;

对于node,n = 其三个成员对齐字节数取最大,即等于t的对齐字节数,也就是 4。

class node

{

char c; //放在位置0,位置区间[0]

temp t; //4(temp的对齐字节数) = n, 那么放置起始位置应该是4的倍数,即4,位置区间为[4~15]

short s; //2 < n,那么放置起始位置应该是2的倍数,即16,位置区间为[16~17]

}

此时成员共占用[0~17]18个字节,还要整体对齐,大小应该是4的倍数,因此大小是20

 

实例5:(默然设置)

对于node,n = 其三个成员对齐字节数取最大,即等于d的对齐字节数,也就是 8。

class node

{

temp t; //放在位置0,位置区间[0~11]

double d; //8(temp的对齐字节数) = n, 那么放置起始位置应该是8的倍数,即16,位置区间为[16~23]

short s; //2 < n,那么放置起始位置应该是2的倍数,即24,位置区间为[24~25]

}

此时成员共占用[0~25]26个字节,还要整体对齐,大小应该是8的倍数,因此大小是32.

 


类继承时的内存对齐

考虑如下类

class A

{

int i;

char c1;

}

class B:public A

{

char c2;

}

class C:public B

{

char c3;

}

sizeof(C)结果是多少呢,gcc和vs给出了不同的结果,分别是8、16

gcc中:C相当于把所有成员i、c1、c2、c3当作是在一个class内部,(先继承后对齐)

vs中:对于A,对齐后其大小是8;对于B,c2加上对齐后的A的大小是9,对齐后就是12;对于C,c3加上对齐后的B大小是13,再对齐就是16 (先对齐后继承)

关于c++对象继承后的内存布局,更详细的分析可以《深度探索参考c++对象模型》第三章

 

参考资料:

zhyjunfov的ChinaUnix博客:gcc的内存对齐

【版权声明】转载请注明出处:http://www.cnblogs.com/TenosDoIt/p/3590491.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/351032.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

matlab sub2ind与ind2sub

sub2ind与ind2sub函数 A [1 2 3; 4 5 6;7,8,9]; >> fsub2ind(size(A), 2, 3) f 8 即把矩阵A中第二行第三列的元素的全下标标识&#xff08;2,3&#xff09;转换为对应的单下标标识8&#xff0c;即该元素从第一列顺次数过去是第八号元素。 而ind2sub则用于把矩阵中…

Spring Boot和Angular 2入门食谱

我主要是一名服务开发人员&#xff0c;必须不时创建一些可传递的UI。 我精通基于AngularJS1的基本UI&#xff0c;并且可以使用之前概述的方法来完成工作。 遗憾的是&#xff0c;随着Angular 2的出现&#xff0c;我不得不将以前的方法抛诸脑后&#xff0c;而现在使用Spring Boot…

Robbers' watch CodeForces - 685A (暴力)

大意: 一天n小时, m分钟, 表以7进制显示, 求表显示数字不同的方案数 注意到小时和分钟部分总长不超过7, 可以直接暴力枚举. 关键要特判0, 0的位数要当做1来处理 #include <iostream> #include <algorithm> #include <cstdio> #include <math.h> #inclu…

什么是javax.ws.rs.core.context? [第5部分]

如何使用Context批注 在什么是javax.ws.rs.core.context的第4部分中&#xff1f; 您学习了如何使用Context批注将HttpServletResponse和HttpServletRequest类注入资源方法。 在本文中&#xff0c;您将学习如何使用其余两个仅在servlet容器中可用的类&#xff0c;它们是&#x…

Linux字符界面和图形界面

Ubuntu图形界面和字符界面的切换 Ubuntu和其他的Linux系统一样&#xff0c;有图形界面和字符界面&#xff0c;同时能够设置默认的启动界面。 linux的显示界面分为命令行的字符界面和图形界面&#xff0c;我们可以设置linux的默认启动的显示界面。然后也可以手动的来回的切换。 …

matlab conv2

conv2函数----------------------------------------1、用法 1. Cconv2(A,B,shape); %卷积滤波 A:输入图像&#xff0c;B:卷积核 假设输入图像A大小为ma x na&#xff0c;卷积核B大小为mb x nb&#xff0c;则 当shapefull时&#xff0c;返回全部二维卷积结…

面试趣味题

题目&#xff1a;一元钱可以买到一瓶水,两个空瓶子可以换一瓶水,小明有20元钱,问最多可以喝多少瓶水? 在面试的时候做了一个这种逻辑题。当时只是要求写出最后的结果。没有要求用代码来实现。我下面准备先分析一下&#xff0c;然后再转换成代码去实现。 根据这个示意图可以简单…

mongodb 持久性_多语言持久性:带有MongoDB和Derby的EclipseLink

mongodb 持久性从现在开始&#xff0c;多语种持久性一直是新闻。 从2011年底开始&#xff0c;在著名的Fowler职位的激励下&#xff0c;我看到了更多更好的主意。 最新的一个是公司内部的学生项目&#xff0c;我们在其中使用Scala作为后端数据&#xff0c;将数据持久存储到Mongo…

linux 动态库文件stripped属性理解

在centos 6.2下用file命令查看文件信息的时候&#xff0c;显示如下&#xff1a; libcom_err.so.2: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, stripped libcrypto.so.10: ELF 64-bit LSB shared object, x86-64, version 1 (SYS…

matlab gradient

gradient函数 >> x[6,9,3,4,0;5,4,1,2,5;6,7,7,8,0;7,8,9,10,0]x 6 9 3 4 0 5 4 1 2 5 6 7 7 8 0 7 8 9 10 0 >> [Fx,Fy]gradient(x) Fx 3.0000 -1.5000 -2.5000 -1.5000…

第六章 传输层

思维导图&#xff1a; 一、 概述 与数据链路层关系 提供可靠的、高效的、性价比高的数据传输输出实体 传输层利用网络层的服务&#xff0c;为它的上层应用层提供服务 网络层与传输层不同点&#xff1a; 网络层运行在由承运商操作的路由器上&#xff0c;因此用户无法真正控制到网…

Kanvas:从您的ANTLR语法生成一个简单的IDE

什么是编辑器&#xff1f; 对我来说&#xff0c;编辑器是我工作中使用的主要工具。 作为语言工程师&#xff0c;我创建新的语言&#xff0c;使用现有的语言&#xff0c;并且需要其他工具来使用它们。 我希望能够在一个定制的IDE中将所有这些黑客一起入侵&#xff0c;我可以为我…

函数名/函数地址/函数指针

转自&#xff1a;http://hi.baidu.com/%C6%BF%D6%D0%B5%C4%C5%AE%CE%D7/blog/item/387db9ddaa54d0a9cd1166fa.html 函数指针&#xff1a;1。指针变量 2。指针变量指向函数 这正如用指针变量可指向整型变量、字符型、数组一样。 在编译时&#xff0c;每一个函数都有一个入口地址…

matlab imaqhwinfo

使用imaqhwinfo函数&#xff0c;来获取电脑上安装的摄像头的名称&#xff0c;比如winvideo&#xff0c;之后可以利用imaqhwinfo(winvideo)来进一步获取设备ID等边信息&#xff0c;这在之后的视频流获取中会用到。获取设备ID之后&#xff08;比如ID为1&#xff09;&#xff0c;可…

第二次作业--熟悉使用工具

GIT地址 https://github.com/ForeveruxGIT用户名 Foreverux学号后五位 62117博客地址 https://www.cnblogs.com/JQloveJX/ 作业链接 https://edu.cnblogs.com/campus/xnsy/SoftwareEngineeringClass1/homework/2793声明&#xff1a;部分内容摘自ChildishChange Part 0. 背景 阿…

什么是javax.ws.rs.core.context? [ 第2部分 ]

如何使用Context批注 在什么是javax.ws.rs.core.context&#xff1f; 您学习了如何使用Context批注从HttpHeaders类的注入实例中检索HTTP标头信息&#xff0c;以及如何从UriInfo实例中检索URI信息&#xff0c;例如URI参数和变量。 在本文中&#xff0c;您将学习如何将Context批…

【题解】Luogu P2347 砝码称重

正经DP题解 一道非常好的背包练手题&#xff08; sto&#xff08;注&#xff1a;原思路来源 SLYZ_0120 的题解&#xff09;orz 开始这道题 1.输入六个数&#xff0c;存进数组中 2.初始化 f 数组为0。 f [ i ] 表示重量为 i 的情况是否出现过&#xff08;下面代码使用的是 int 数…

matlab 获取视频图像的信息

获取视频图像的信息可以通过get函数来获取&#xff0c;如get(vid)或者get(getselectedsource(vid))。使用set函数可以设置摄像头获取的图像的一些属性值&#xff0c;也可以直接使用结构数组的“点”来赋值&#xff0c;比如&#xff0c;要持续通过摄像头获取图像&#xff0c;则可…

tomcat使用ssl_使用SSL和Spring Security保护Tomcat应用程序的安全

tomcat使用ssl如果您看过我的上一个博客&#xff0c;您会知道我列出了Spring Security可以做的十件事 。 但是&#xff0c;在开始认真使用Spring Security之前&#xff0c;您真正要做的第一件事就是确保您的Web应用使用正确的传输协议&#xff0c;在这种情况下为HTTPS –毕竟&a…

matlab delete、clf、cla、close、closereq删除对象

matlab中删除对象 删除对象 &#xff08;1&#xff09;delete&#xff1a;删除文件或对象图形 删除文件对象h的格式为&#xff1a;delete(filename)或delete filename 删除图形对象h的格式为&#xff1a;delete(h); 若要无条件删除所有的图形对象&#xff0c;则&#xff1a;set…