VC内存对齐准则(Memory alignment)

***************************************************

更多精彩,欢迎进入:http://shop115376623.taobao.com

***************************************************


本文所有内容在建立在一个前提下:使用VC编译器。着重点在于:VC的内存对齐准则;同样的数据, 不同的排列有不同的大小,另外在有虚函数或虚拟继承情况下又有如何影响?

内存对齐?!What?Why?

对于一台32位的机器来说如何才能发挥它的最佳存取效率呢?当然是每次都读4字节(32bit)(一个字节8位,一次读取4个字节,刚好满负荷读取), 这样才可以让它的bus处于最高效率。实际上它也是这么做的,即使你只需要一个字节,它也是 读一个机器字长(这儿是32bit)。更重要的是,有的机器在存取或存储数据的时候它要求数据 必须是对齐的,何谓对齐?它要求数据的地址从4的倍数开始,如若不然,它就报错。还有的机 器它虽然不报错,但对于一个类似int变量,假如它横跨一个边界的两端,那么它将要进行两次 读取才能获得这个int值。比方它存储在地址为2~5的四个字节中,那么要读取这个int,将要 进行两次读取,第一次读取0~3四个字节,第二次读取4~7四个字节。但是如果我们把这个整 形的起始地址调整到0,4,8…呢?一次存取就够了!这种调整就是内存对齐了。我们也可以依次 类推到16位或64位的机器上。

边界该如何调整

对于32位的机器来说,它当然最渴望它的数据的大小都是4 Byte或者4的倍数Byte,这样它就能 最有效率的存取数据,当然如果数据小于4Byte,那也是没问题的。那么编译器要做的便是尽量满 足这个要求。

这两天我断续对VC做了一些实验,并总结如下三条准则,你要明白的是这并非来自微软的官方文 档,但我自以为这些准则或许不全但应该都是正确的:

  • 变量存放的起始位置2应为变量的大小与规定对齐量1中较小者的倍数。例如,假 设规定对齐量为4,那么char(1byte)变量应该存储在偏移量为1的倍数的地方,而整形变 量(4byte)则是从偏移量为4的倍数的地方,而double(8 byte)也同样应存储在偏移量为 4的倍数的地方,为什么不是8?因为规定对齐量默认值为4,而4 < 8。在VC中默认对齐量 为8,而非4
  • 结构体整体的大小也应该对齐,对齐依照规定对齐量与最大数据成员两者中较小的进行。
  • Vptr影响对齐而VbcPoint(Virtual base class pointer)不影响。

一个实例

对于类T:

class T{char c;int i;double  d;};

将其sizeof输出后的大小为16,其内存布局如图T.变量c从偏移量为0开始存储,而整形i第一个 符号条件的偏移量为4,double型d的第一个符号条件的为8。整个对象的大小为16,不需要再进 行额外的对齐。

图T(类T 的内存布局) :

同样的数据,不同的大小

再看类L,它与T存储同样类型的数据,仅仅是顺序不同罢了,那么它sizeof输出的大小是多少呢?

类L:

class L{char c;double  d;int i;};

它sizeof后的结果或许会令你大吃一惊,或许不会(如果你有认真读前面的两条准则)。L sizeof后的结果是24!同样是一个int,一个char,一个double却整整多出了8个字节。这期间 发生了什么?我们依据前面两条规则来看看。C存储于0的位置,1~7都不能整除8,所以d存储 在8~15,16给i正好合适,i存储在16~19。总共花费了20个字节,抱歉不是8的倍数,还得补 齐4个。现在你可以看看图L的关于类L的内存布局,再比较一下类L和类T的内存布局。

图L(类L的布局)

我得出了这样一条并不权威的结论,因为我还没听有人这样说过:在声明数据成员的时候,将 最大字节数的变量放在最前面3,切忌不要将大小差距很大的类型交替声明。

Vptr影响对齐而VbcPoint(Virtual base class pointer)不影响

前面的实例只涉及前两条准则,现在我们来看看第三条的两个实例:

class X{char a;};
class Y: virtual public X{};

Y的大小为:a占一个字节,VbcPoint(我称他为虚基类指针)占四个字节。我们不论a与VbcPoint 的位置如何摆放,如果将VbcPoint等同于一个成员数据来看的话,sizeof(Y)都应该为8.实际上 它是5!就我目前的水平,我只能先将其解释为VbcPoint不参与对齐。

对于vptr这个问题则不存在:

class X{char a;virtual int vfc(){};}

sizeof(X)的大小确实为8.

关于#pragma pack(n)

用#pragma pack(n)改变规定对齐量试试眨眼


  1. 规定对齐量:实际上并没有这么一个名词,是我为了方便而造出来的。在VC中这个“规定对齐量”会有一个默认值,这个默认值一般为8,我原来一直以为这个值以为是4,至于它为什么为8,我现在还不知道。。我们也可以通过#pargma pack(n)来规定这个值,目前n可以为1,2,4,8,16。 ↩

  2. 这个起始位置指的是相对于结构体(类)来说的。 ↩

  3. 此处有一点问题,这个问题由独酌逸醉提出,他认为将最小的数据放在最前面可能会更好,我们有进行过讨论,但可惜的是由于在2011/11/24日数据库丢失,我只能用备份还原,所以丢失了一些数据,无疑,本文的评论也在其中。不过我对这个问题映像深刻,因为我在写这篇博客的时候便困惑于到底成员是应该放在之前还是之后,因为这两种情况我都找不到强有力的理由来支撑它们。后来使我确信从大到小排列好于从小到大排列的理由在于,从大到小排列一般无需成员之间的对齐,唯一的对齐工作是最后进行的整个结构体对齐的工作。毫无疑问的是,这应该是最节省内存的方式。再之后,独酌提出从小到大可能好些,虽然没有给出有说服力的理由,但却使我无比困惑,我当时虽然认为从大到小的排列更有优势,但却实在想不出一个实例能使得它优于从小到大排列的。不过最终我击垮了自己的理由,在继承状况下从大到小排列很容易被打破,比方,基类的成员为一个char,继承类的成员为double,int,char虽然基类和继承类都是按从大到小的顺序排列的,但是继承类的内存布局最终会使char,double,int,char,此时既不能避免成员对齐,又导致后面的结构体对齐。暂时获得的最终结果是从小到大排列是更好的一种排列方式。(2011/12/31增补) 

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

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

相关文章

[redis设计与实现][7]基本数据结构——对象

Redis对基础数据类型进行了封装&#xff0c;构建出上层的对象系统&#xff0c;这个系统包含&#xff1a;字符串对象、列表对象、哈希对象、集合对象和有序集合对象。 Redis对象结构&#xff1a; [cce lang”c”] typedef struct redisObject { //类型 unsigned type:4; //编码 …

Linux中samba的权限详解,活用三种权限 理解Samba的权限控制

在企业内网开发环境方面&#xff0c;文件服务器是一个非常重要的环节。在这当中&#xff0c;Samba服务器由于其权限控制的高度灵活性&#xff0c;在这里抚琴煮酒会进行一些列详细的说明。之前我们已经介绍了Samba服务器一些入门和基本的更换用户、端口监听、列表控制等技巧&…

安卓基础01

安卓基础01SDK System images 这是在创建模拟器时需要的system image&#xff0c;也就是在创建模拟器时CPU/ABI项需要选择的&#xff0c;下载并解压后&#xff0c;将解压出的整个文件夹复制或者移动到 your sdk 路径/system-images文件夹下即可&#xff0c; 如果没有 system-im…

C++存储区域基础概念详解

*************************************************** 更多精彩&#xff0c;欢迎进入&#xff1a;http://shop115376623.taobao.com *************************************************** 以下详解来自&#xff1a; http://blog.163.com/zb_075/blog/static/3734032820115110…

创建、修改、删除表总结

一、创建表 CREATE TABLE <表名> &#xff08;<列名><数据类型>[列级完整性约束条件] [&#xff0c;<列名> <数据类型>[列级完整性约束条件]] … [&#xff0c;表级完整性约束条件]&#xff09;&#xff1b; 如果完整性约束条件涉及到该表的多个…

linux 编译查看链接库详情,Linux环境下的编译,链接与库的使用

链接参数控制链接器中提供了-dn -dy 参数来控制使用的是动态库还是静态库&#xff0c;-dn表示后面使用的是静态库&#xff0c;-dy表示使用的是动态库例:g -Lpath -Wl,-dn -lx -Wl,-dy -lpthread 这样如果在path路径下有libx.so和libx.a这个时候只会用到 libx.a.注意在最后的地…

在C++中用虚函数的作用是什么? 为什么要用到虚函数?

***************************************************更多精彩&#xff0c;欢迎进入&#xff1a;http://shop115376623.taobao.com***************************************************虚函数联系到多态&#xff0c;多态联系到继承。所以本文中都是在继承层次上做文章。没了继…

mysql 主主互备实现

今天星期天&#xff0c;么事就写个MYSQL的主主架构的博客&#xff0c;原理如下图&#xff0c;不是我画的网上找的。主机作用操作系统mysql版本对应IPvip数据库mysqlA(主)centos6.4mysql 5.5.48192.168.48.129192.168.48.126mysqlB(备)centos6.4mysql 5.5.48192.168.48.132一&am…

Linux Deepin 版本大全,Deepin下载-Deepin linuxv20.0 官方版下载-6188手游网

Deepin linux安装准备一&#xff1a;为 Deepin 留出硬盘空间以便安装。1.打开磁盘管理(Windows 徽标上右键单击&#xff0c;选择磁盘管理)。2.选中一个分区(空闲空间大于 30G)&#xff0c;我选择的是 C 盘&#xff0c;因为是固态硬盘所以安装启动会快很多。磁盘 1 的 200G 分区…

动手实践 Linux VLAN - 每天5分钟玩转 OpenStack(13)

本节我们来看如何在实验环境中实施和配置如下 VLAN 网络 配置 VLAN 编辑 /etc/network/interfaces&#xff0c;配置 eth0.10、brvlan10、eth0.20 和 brvlan20。 下面用 vmdiff 展示了对 /etc/network/interfaces 的修改 重启宿主机&#xff0c;ifconfig 各个网络接口 用 brct…

Socket的3次握手链接与4次断开握手

*************************************************** 更多精彩&#xff0c;欢迎进入&#xff1a;http://shop115376623.taobao.com *************************************************** 连接握手&#xff1a; 1.客户端发送建立连接请求 &#xff08;发送请求&#xff09;2.…

Linux桌面需要强制访问控制,RHCSA 系列(十三): 在 RHEL 7 中使用 SELinux 进行强制访问控制...

RHCSA 认证&#xff1a;SELinux 精要和控制文件系统的访问尽管作为第一级别的权限和访问控制机制是必要的&#xff0c;但它们同样有一些局限&#xff0c;而这些局限则可以由安全增强 Linux(Security Enhanced Linux&#xff0c;简称为 SELinux)来处理。这些局限的一种情形是&am…

使用canvas实现擦玻璃效果

体验效果:http://hovertree.com/texiao/html5/25/效果图&#xff1a;代码如下&#xff1a; <!DOCTYPE html> <html> <head lang"zh"> <meta name"viewport" content"initial-scale1.0, maximum-scale1.0, user-scalableno, widt…

如何计算时间复杂度

*************************************************** 更多精彩&#xff0c;欢迎进入&#xff1a;http://shop115376623.taobao.com *************************************************** 求解算法的时间复杂度的具体步骤是&#xff1a; ⑴ 找出算法中的基本语句&#xff1b;…

linux显示系统信息软件下载,linux查看系统信息软件安装信息命令学习笔记

查看LINUX安装版本[rootlocalhost etc]# unameLinux[rootlocalhost etc]# uname -aLinux localhost.localdomain 2.6.32-279.11.1.el6.i686 #1 SMP Tue Oct 16 14:40:53 UTC 2012 i686 i686 i386 GNU/Linux[rootlocalhost etc]# cat /proc/versionLinux version 2.6.32-279.11.…

Bzoj 2662: [BeiJing wc2012]冻结 dijkstra,堆,分层图,最短路

2662: [BeiJing wc2012]冻结 Time Limit: 3 Sec Memory Limit: 128 MBSubmit: 647 Solved: 348[Submit][Status][Discuss]Description “我要成为魔法少女&#xff01;” “那么&#xff0c;以灵魂为代价&#xff0c;你希望得到什么&#xff1f;” “我要将有关魔法和奇…

[转]opencv学习资料

转自&#xff1a;http://blog.csdn.net/poem_qianmo/article/details/20537737 1&#xff1a;Mat imread(const string& filename, intflags1 ); eg: Mat image0imread("dota.jpg",CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR);//载入最真实的图像 ge1i…

linux servlet 乱码问题,Servlet一次乱码排查后的总结

由来在写一个小小的表单提交功能的时候&#xff0c;出现了乱码&#xff0c;很奇怪request上来的参数全部是乱码&#xff0c;而从数据库查询出来的中文显示到页面正常&#xff0c;锁定肯定是request对象那里出了问题。后来经过排查&#xff0c;发现是我封装的框架中出了问题&…

C/C++回调函数

*************************************************** 更多精彩&#xff0c;欢迎进入&#xff1a;http://shop115376623.taobao.com *************************************************** 对于很多初学者来说&#xff0c;往往觉得回调函数很神秘&#xff0c;很想知道回调函数…

Linux 命令[2]:mkdir

make directories mkdir -p [目录名] -p 递归创建 [rootlocalhost ~]# mkdir -p test [rootlocalhost ~]# ls anaconda-ks.cfg install.log install.log.syslog test 当然只创建一个目录 -p 是可以省略的 注&#xff1a;如果创建多级目录没有 -p 会报错 如&#xff1a; [roo…