mysql字节对齐_结构体字节对齐(转)

结构体字节对齐

在用sizeof运算符求算某结构体所占空间时,并不是简单地将结构体中所有元素各自占的空间相加,这里涉及到内存字节对齐的问题。从理论上讲,对于任何变量的访问都可以从任何地址开始访问,但是事实上不是如此,实际上访问特定类型的变量只能在特定的地址访问,这就需要各个变量在空间上按一定的规则排列,而不是简单地顺序排列,这就是内存对齐。

内存对齐的原因:

1)某些平台只能在特定的地址处访问特定类型的数据;

2)提高存取数据的速度。比如有的平台每次都是从偶地址处读取数据,对于一个int型的变量,若从偶地址单元处存放,则只需一个读取周期即可读取该变量;但是若从奇地址单元处存放,则需要2个读取周期读取该变量。

在C99标准中,对于内存对齐的细节没有作过多的描述,具体的实现交由编译器去处理,所以在不同的编译环境下,内存对齐可能略有不同,但是对齐的最基本原则是一致的,对于结构体的字节对齐主要有下面两点:

1)结构体每个成员相对结构体首地址的偏移量(offset)是对齐参数的整数倍,如有需要会在成员之间填充字节。编译器在为结构体成员开辟空间时,首先检查预开辟空间的地址相对于结构体首地址的偏移量是否为对齐参数的整数倍,若是,则存放该成员;若不是,则填充若干字节,以达到整数倍的要求。

2)结构体变量所占空间的大小是对齐参数大小的整数倍。如有需要会在最后一个成员末尾填充若干字节使得所占空间大小是对齐参数大小的整数倍。

注意:在看这两条原则之前,先了解一下对齐参数这个概念。对于每个变量,它自身有对齐参数,这个自身对齐参数在不同编译环境下不同。下面列举的是两种最常见的编译环境下各种类型变量的自身对齐参数

从上面可以发现,在windows(32)/VC6.0下各种类型的变量的自身对齐参数就是该类型变量所占字节数的大小,而在linux(32)/GCC下double类型的变量自身对齐参数是4,是因为linux(32)/GCC下如果该类型变量的长度没有超过CPU的字长,则以该类型变量的长度作为自身对齐参数,如果该类型变量的长度超过CPU字长,则自身对齐参数为CPU字长,而32位系统其CPU字长是4,所以linux(32)/GCC下double类型的变量自身对齐参数是4,如果是在Linux(64)下,则double类型的自身对齐参数是8。

除了变量的自身对齐参数外,还有一个对齐参数,就是每个编译器默认的对齐参数#pragma pack(n),这个值可以通过代码去设定,如果没有设定,则取系统的默认值。在windows(32)/VC6.0下,n的取值可以为1、2、4、8,默认情况下为8。在linux(32)/GCC下,n的取值只能为1、2、4,默认情况下为4。注意像DEV-CPP、MinGW等在windows下n的取值和VC的相同。

了解了这2个概念之后,可以理解上面2条原则了。对于第一条原则,每个变量相对于结构体的首地址的偏移量必须是对齐参数的整数倍,这句话中的对齐参数是取每个变量自身对齐参数和系统默认对齐参数#pragma pack(n)中较小的一个。举个简单的例子,比如在结构体A中有变量int a,a的自身对齐参数为4(环境为windows/vc),而VC默认的对齐参数为8,取较小者,则对于a,它相对于结构体A的起始地址的偏移量必须是4的倍数。

对于第二条原则,结构体变量所占空间的大小是对齐参数的整数倍。这句话中的对齐参数有点复杂,它是取结构体中所有变量的对齐参数的最大值和系统默认对齐参数#pragma pack(n)比较,较小者作为对齐参数。举个例子假如在结构体A中先后定义了两个变量int a;double b;对于变量a,它的自身对齐参数为4,而#pragma pack(n)值默认为8,则a的对齐参数为4;b的自身对齐参数为8,而#pragma pack(n)的默认值为8,则b的对齐参数为8。由于a的最终对齐参数为4,b的最终对齐参数为8,那么两者较大者是8,然后再拿8和#pragma pack(n)作比较,取较小者作为对齐参数,也就是8,即意味着结构体最终的大小必须能被8整除。

下面是测试例子:

注意:以下例子的测试结果均在windows(32)/VC下测试的,其默认对齐参数为8

复制代码

/测试sizeof运算符 2011.10.1/

include

using namespace std;

//#pragma pack(4) //设置4字节对齐

//#pragma pack() //取消4字节对齐

typedef struct node1

{

int a;

char b;

short c;

}S1;

typedef struct node2

{

char a;

int b;

short c;

}S2;

typedef struct node3

{

int a;

short b;

static int c;

}S3;

typedef struct node4

{

bool a;

S1 s1;

short b;

}S4;

typedef struct node5

{

bool a;

S1 s1;

double b;

int c;

}S5;

int main(int argc, char *argv[])

{

cout<

S1 s1;

S2 s2;

S3 s3;

S4 s4;

S5 s5;

cout<

return 0;

}

复制代码

下面解释一下其中的几个结构体字节分配的情况

比如对于node2

typedef struct node2

{

char a;

int b;

short c;

}S2;

sizeof(S2)=12;

对于变量a,它的自身对齐参数为1,#pragma pack(n)默认值为8,则最终a的对齐参数为1,为其分配1字节的空间,它相对于结构体起始地址的偏移量为0,能被4整除;

对于变量b,它的自身对齐参数为4,#pragma pack(n)默认值为8,则最终b的对齐参数为4,接下来的地址相对于结构体的起始地址的偏移量为1,1不能够整除4,所以需要在a后面填充3字节使得偏移量达到4,然后再为b分配4字节的空间;

对于变量c,它的自身对齐参数为2,#pragma pack(n)默认值为8,则最终c的对齐参数为2,而接下来的地址相对于结构体的起始地址的偏移量为8,能整除2,所以直接为c分配2字节的空间。

此时结构体所占的字节数为1+3+4+2=10字节

最后由于a,b,c的最终对齐参数分别为1,4,2,最大为4,#pragma pack(n)的默认值为8,则结构体变量最后的大小必须能被4整除。而10不能够整除4,所以需要在后面填充2字节达到12字节。其存储如下:

|char|----|----|----| 4字节

|--------int--------| 4字节

|--short--|----|----| 4字节

总共占12个字节

对于node3,含有静态数据成员

typedef struct node3

{

int a;

short b;

static int c;

}S3;

则sizeof(S3)=8.这里结构体中包含静态数据成员,而静态数据成员的存放位置与结构体实例的存储地址无关(注意只有在C++中结构体中才能含有静态数据成员,而C中结构体中是不允许含有静态数据成员的)。其在内存中存储方式如下:

|--------int--------| 4字节

|--short-|----|----| 4字节

而变量c是单独存放在静态数据区的,因此用siezof计算其大小时没有将c所占的空间计算进来。

而对于node5,里面含有结构体变量

复制代码

typedef struct node5

{

bool a;

S1 s1;

double b;

int c;

}S5;

复制代码

sizeof(S5)=32。

对于变量a,其自身对齐参数为1,#pragma pack(n)为8,则a的最终对齐参数为1,为它分配1字节的空间,它相对于结构体起始地址的偏移量为0,能被1整除;

对于s1,它的自身对齐参数为4(对于结构体变量,它的自身对齐参数为它里面各个变量最终对齐参数的最大值),#pragma pack(n)为8,所以s1的最终对齐参数为4,接下来的地址相对于结构体起始地址的偏移量为1,不能被4整除,所以需要在a后面填充3字节达到4,为其分配8字节的空间;

对于变量b,它的自身对齐参数为8,#pragma pack(n)的默认值为8,则b的最终对齐参数为8,接下来的地址相对于结构体起始地址的偏移量为12,不能被8整除,所以需要在s1后面填充4字节达到16,再为b分配8字节的空间;

对于变量c,它的自身对齐参数为4,#pragma pack(n)的默认值为8,则c的最终对齐参数为4,接下来相对于结构体其实地址的偏移量为24,能够被4整除,所以直接为c分配4字节的空间。

此时结构体所占字节数为1+3+8+4+8+4=28字节。

对于整个结构体来说,各个变量的最终对齐参数为1,4,8,4,最大值为8,#pragma pack(n)默认值为8,所以最终结构体的大小必须是8的倍数,因此需要在最后面填充4字节达到32字节。其存储如下:

|--------bool--------| 4字节

|---------s1---------| 8字节

|--------------------| 4字节

|--------double------| 8字节

|----int----|---------| 8字节

另外可以显示地在程序中使用#pragma pack(n)来设置系统默认的对齐参数,在显示设置之后,则以设置的值作为标准,其它的和上面所讲的类似,就不再赘述了,读者可以自行上机试验一下。如果需要取消设置,可以用#pragma pack()来取消。

作者:海子

出处:http://www.cnblogs.com/dolphin0520/

本博客中未标明转载的文章归作者海子和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

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

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

相关文章

python docx 合并文档 图片_不再为处理PDF烦恼,python处理操作PDF全攻略

本篇聊下Python对pdf的各种操作&#xff0c;包含pdf转word&#xff0c;pdf转图片&#xff0c;pdf翻转&#xff0c;加密&#xff0c;加水印等。pdf转换word文档 保留格式pdf转换为word文档&#xff0c;被大众经常使用的是纯Python库pdfminer和python-docx搭配使用&#xff0c;不…

new blog

new blog转载于:https://www.cnblogs.com/uuzlove/p/9336405.html

windows server 2012 初安装体验

昨天晚上的windows server 2012 已时行 了发布了&#xff0c;为之在之前我已进行了下载测试安装&#xff0c;本来晚间想用来在虚拟机下进行安装VM-tool工具的&#xff0c;但是却因种种原因没有成功&#xff0c;为之补一下前面没有安装的过程截图。 进入下载页后&#xff0c;下载…

python 多进程 调用模块内函数_python子进程模块subprocess详解与应用实例 之一

分类&#xff1a; Python/Ruby 2014-09-09 10:59:42 subprocess--子进程管理器 一、subprocess 模块简介 subprocess最早是在2.4版本中引入的。 subprocess模块用来生成子进程&#xff0c;并可以通过管道连接它们的输入/输出/错误&#xff0c;以及获得它们的返回值。 它用来代替…

安卓APP_ 控件(1)—— TextView

摘自&#xff1a;安卓APP_ 控件&#xff08;1&#xff09;—— TextView 作者&#xff1a;丶PURSUING 发布时间&#xff1a; 2021-03-28 21:53:49 网址&#xff1a;https://blog.csdn.net/weixin_44742824/article/details/115283233 本文为学习笔记&#xff0c;是安卓APP学习的…

python udp 大文件_Python:通过UDP发送大对象

我是套接字编程的新手&#xff0c;最近为它挑选了Python。我有几个问题&#xff0c;我似乎无法找到明确的答案。Python&#xff1a;通过UDP发送大对象我正在研究通过UDP发送数据&#xff0c;并写了一个简单的python脚本来做到这一点。可以很好地发送小对象(准确地说是小腌制对象…

Flask入门系列(转载)

一、入门系列&#xff1a; Flask入门系列(一)–Hello World 项目开发中&#xff0c;经常要写一些小系统来辅助&#xff0c;比如监控系统&#xff0c;配置系统等等。用传统的Java写&#xff0c;太笨重了&#xff0c;连PHP都嫌麻烦。一直在寻找一个轻量级的后台框架&#xff0c;学…

iphone3G恢复到3.1.2遇到的问题

1.报错1015 2.进入DFU模式&#xff0c;刷到下载数据停止不动。 3.进入菠萝&#xff0c;进度条走到最后停止不动。 4.红雪走到waiting for reboot停止不动。 针对上述问题&#xff1a; 首先&#xff0c;要找到完全对应手机系统原版本的固件。然后&#xff0c;红雪进入DFU模式刷机…

用python做数据分析pdf_利用python进行数据分析pdf

利用python进行数据分析pdf微盘下载&#xff01;《利用python进行数据分析》利用Python实现数据密集型应用由浅入深帮助读者解决数据分析问题~适合刚刚接触Python的分析人员以及刚刚接触科学计算的Python程序员。利用python进行数据分析简介&#xff1a; 还在苦苦寻觅用Python控…

安卓APP_ 控件(2)—— Button

摘自&#xff1a;安卓APP_ 控件&#xff08;2&#xff09;—— Button 作者&#xff1a;丶PURSUING 发布时间&#xff1a; 2021-03-29 14:20:54 网址&#xff1a;https://blog.csdn.net/weixin_44742824/article/details/115290501 开篇&#xff1a;安卓APP_ 控件&#xff08;1…

python 列表自定义排序_自定义排序的Python列表

我有一个dicts列表: ldicts = [{name: 120-150}, {name: 90-120}, {name: 150-180}, {name: >= 180}, {name: <90}, {name: total}] 我想按值升序对其进行排序,以便输出如下: sortedldicts = [{name: total}, {name: <90}, {name: 90-120},{name: 120-150}, {name: …

HTML DOM知识点补充:

DOM Console 控制台对象提供了浏览器的debug的方法支持。 常用的&#xff1a;console.log()。 ⚠️coffeescript中&#xff0c;这个方法不加括号。 DOM Document 当一个HTML document加载到浏览器上&#xff0c;它就成为了一个document object。 它是root node 提供了大量docum…

python汇率编程_【菜鸟学Python】案例一:汇率换算

汇率换算V1.0 案例描述&#xff1a; 设计一个汇率换算器程序&#xff0c;其功能是将外币换算成人民币&#xff0c;或者相反 案例分析&#xff1a; 分析问题&#xff1a;分析问题的计算部分&#xff1b; 确定问题&#xff1a;将问题划分为输入、处理及输出部分&#xff1b; 设计…

2013年全球最佳工作

&#xfeff;&#xfeff;2013年即将到来&#xff0c;在新的一年中软件开发人士将继续保持良好的发展态势&#xff0c;通过信息技术及分析业务为企业带来竞争优势。系统分析师、网络/系统管理员、网络架构师以及数据库管理员也纷纷名列榜单前十五位。硅谷与华盛顿特区地铁体系则…

安卓APP_ 控件(3)—— EditText

摘自&#xff1a;安卓APP_ 控件&#xff08;3&#xff09;—— EditText 作者&#xff1a;丶PURSUING 发布时间&#xff1a; 2021-03-29 18:43:40 网址&#xff1a;https://blog.csdn.net/weixin_44742824/article/details/115305883 开篇&#xff1a;安卓APP_ 控件&#xff08…

python做游戏怎么实现窗口_python和py游戏窗口类

你在draw_sprite()中有事件循环&#xff0c;所以它一直运行到游戏结束&#xff0c;window.set_background永远不会执行。在您的代码构造不正确。在我试着更正它&#xff0c;稍后再发送代码。在编辑&#xff1a;如何组织代码的简单示例。在现在它在一个文件中。在Pygame中总是一…

python十种日期格式_Python中最常用的日期时间格式

在日常开发的时候&#xff0c;我们经常会遇到时间处理的问题&#xff0c;代码示例爬虫过来的时间处理&#xff0c;代码示例对库内的数据进行时间维度的统计等。虽然是个很简单的东西&#xff0c;但每次用的时候都难免要再查一查&#xff0c;其实这就是基础不夯实的表现。趁着今…

精通QTP-自动化测试技术领航

精通QTP-自动化测试技术领航

如何使得账户密码永不过期

如何使得账户密码永不过期 原文:如何使得账户密码永不过期可以通过以下vbs脚本做的使得账户密码永不过期 dim users获取所有用户set users getobject("winmgmts:{impersonationlevelimpersonate}").instancesof("win32_useraccount")for each user in use…

python随机数比大小_1到范围内的随机数系统最大大小总是1模2^10

我试图通过使用频率测试、运行测试和卡平方检验来找到Python(2.7.10)中可用的prng的统计特性。在为了进行频率测试&#xff0c;我需要将生成的随机数转换为其二进制表示形式&#xff0c;然后计算1和{}的分布。我在python控制台上试验随机数的二进制表示&#xff0c;并观察到这种…