[C++]字节对齐与结构体大小.pdf

您所在的位置:网站首页 结构体字节对齐的作用 [C++]字节对齐与结构体大小.pdf

[C++]字节对齐与结构体大小.pdf

2022-03-24 00:16| 来源: 网络整理| 查看: 265

《[C++]字节对齐与结构体大小.pdf》由会员分享,可在线阅读,更多相关《[C++]字节对齐与结构体大小.pdf(12页珍藏版)》请在点石文库上搜索。

1、 C+字节对齐与结构体大小 说明: 结构体的 sizeof 值 ,并不是简单的将其中各元素所占字节相加,而是要考虑到存储空间的字节对齐问题。这 些问题在平时编程的时候也确实不怎么用到,但在一些笔试面试题目中出是常常出现,对 sizeof 我们将在 另一篇文章中总结,这篇文章我们只总结结构体的 sizeof,报着不到黄河心不死的决心,终于完成了总结, 也算是小有收获,拿出来于大家分享,如果有什么错误或者没有理解透的地方还望能得到提点,也不至于 误导他人。 别忘了这里 http:/ 一、解释 现代计算机中内存空间都是按照 byte 划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开 始,。

2、但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,这就需要各种类型数据按照一 定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。 各个硬件平台对存储空间的处理上有很大的不同。一些平台对 某些特定类型的数据只能从某些特定地址开 始存取。比如有些架构的 CPU 在访问 一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编 程必须保证字节对齐 .其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对 数据存 放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个 int 型(假设为 32 位系统)如果存放在偶地址开始的地方,那 。

3、么一个读周期就可以读出这 32bit,而如果存放在奇地址开 始的地方,就需要 2 个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该 32bit 数据。 二、准则 其实字节对齐的细节和具体编译器实现相关,但一般而言,满足 三个准则: 1. 结构体变量的首地址能够被其最宽基本类型成员的大小所整除; 2. 结构体每个成员相对于结构体首地址的偏移量都是成员大小的整数倍,如有需要编译器会在成员之间加 上填充字节; 3. 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上 填充字节。 三、基本概念 字节对齐:计算机存储系统中以 Byte 为单位存储数据,不同。

4、数据类型所占的空间不同,如:整型( int)数 据占 4 个字节,字符 型( char)数据占一个字节,短整型( short)数据占两个字节,等等。计算机为了快 速的读写数据,默认情况下将数据存放在某个地址的起始位置,如:整型数据( int)默认存储在地址能被 4 整除的起始位置,字符型数据( char)可以存放在任何地址位置(被 1 整除),短整型( short)数据存储 在地址能被 2 整除的起始位置。这就是默认字节对齐方式。 四、结构体长度求法 1.成员都相同时(或含数组且数组数据类型同结构体其他成员数据类型): 结构体长度 =成员数据类型长度 成员个数(各成员长度之和) ; 结构体中数。

5、组长 度 =数组数据类型长度 数组元素个数; 2.成员不同且不含其它结构体时 ; (1).分析各个成员长度; (2).找出最大长度的成员长度 M(结构体的长度一定是该成员的整数倍); (3).并按最大成员长度出现的位置将结构体分为若干部分; (4).各个部分长度一次相加,求出大于该和的最小 M 的整数倍即为该部分长度 (5).将各个部分长度相加之和即为结构体长度 3.含有其他结构体时: (1).分析各个成员长度; (2).对是结构体的成员,其长度按 b 来分析,且不会随着位置的变化而变化; (3).分析各个成员 的长度(成员为结构体的分析其成员长度),求出最大值; (4).若长度最大成员在为结。

6、构体的成员中,则按结构体成员为分界点分界; 其他成员中有最大长度的成员,则该成员为分界点; 求出各段长度,求出大于该和的最小 M的整数倍即为该部分长度 (5).将各个部分长度相加之和即为结构体长度 五、空结构体 struct S5 ; sizeof( S5 ); / 结果为 1 “空结构体 ”(不含数据成员)的大小不为 0,而是 1。试想一个 “不占空间 ”的变量如何被取地址、两个不同 的 “空结构体 ”变量又如何得以区分呢于是, “空结构体 ”变量也得被存储,这样编译器也就只能为其分配一个 字节的空间用于 占位 了。 六、有 static 的结构体 struct S4 char a; lon。

7、g b; static long c; /静态 ; 静态变量存放在全局数据区内,而 sizeof 计算栈中分配的空间的大小,故不计算在内, S4 的大小为 4+4=8。 七、举例说明 1.举例 1 很显然默认对齐方式会浪费很多空间,例如如下结构: struct student char name5; int num; short score; 本来只用了 11bytes( 5+4+2)的空间,但是由于 int 型默认 4 字节 对齐,存放在地址能被 4 整除的起始位 置,即:如果 name5从 0 开始存放,它占 5bytes,而 num 则从第 8(偏移量)个字节开始存放。所以 sizeof。

8、(student)=16。于是中间空出几个字节闲置着。但这样便于计算机快速读写数据,是一种以空间换取 时间的方式。其数据对齐如下图: |char|char|char|char| |char|-|-|-| |-int-| |-short-|-|-| 如果我们将结构体中变量的顺序改变为: struct student int num; char name5; short score; 则, num 从 0 开始存放,而 name 从第 4(偏移量)个字节开始存放,连续 5 个字节, score 从第 10(偏 移量)开始存放,故 sizeof(student)=12。其数据对齐如下图: |-int。

9、-| |char|char|char|char| |char|-|-short-| 如果我们将结构体中变量的顺序再次改为为: struct student int num; short score; char name5; 则, sizeof(student)=12。其数据对齐如下图: |-int-| |-short-|char|char| |char|char|char|-| 2.举例 2 ( 1) struct test1 int a; int b4; ; sizeof(test1)=sizeof(int)+4*sizeof(int)=4+4*4=20; ( 2) struct test2。

10、 char a; int b; double c; bool d; ; 分析:该结构体最大长度 double 型,长度是 8,因此结构体长度分两部分: 第一部分是 a、 b、 c 的长度和,长度分别为 1, 4, 8,则该部分长度和为 13,取 8 的大于 13 的最小倍 数为 16; 第二部分为 d,长度为 1,取大于 1 的 8 的最小倍数为 8, 两部分和为 24,故 sizeof(test2)=24; ( 3) struct test3 char a; test2 bb;/见上题 int cc; 分析:该结构体有三个成员,其中第二个 bb 是类型为 test2 的结构体,长度为 24,。

11、且该结构体最大长度成 员类型为 double 型,以后成员中没有 double 型,所以按 bb 分界为两部分: 第一部分有 a 、 bb 两部分, a 长度为 1, bb 长度为 24,取 8 的大于 25 的最小倍数 32; 第二部分有 cc,长度为 4,去 8 的大于 4 的最小倍数为 8; 两部分之和为 40,故 sizeof(test3)=40; ( 4) struct test4 char a; int b; ; struct test5 char c; test4 d; double e; bool f; ; 求 sizeof(test5) 分析: test5 明显含有结构体 t。

12、est4,按例 2 容易知道 sizeof(test4)=8,且其成员最大长度为 4;则结构体 test5 的最大成员长度为 8(double 型 ),考试 .大提示 e 是分界点,分 test5 为两部 分: 第一部分由 c 、 d、 e 组成,长度为 1、 8、 8,故和为 17,取 8 的大于 17 的最小倍数为 24; 第二部分由 f 组成,长度为 1,取 8 的大于 1 的最小倍数为 8, 两部分和为 32,故 sizeof(test5)=24+8=32; 八、 union union 的长度取决于其中的长度最大的那个成员变量的长度。 即 union 中成员变量是重叠摆放的,其开始 。

13、地址相同。 其实 union(共用体 )的各个成员是以同一个地址开始存放的 ,每一个时刻只可以存储一个成员 ,这样就要求它 在分配内存单元时候要满足两点 : 1.一般而言 ,共用体类型实际占用存储空间为其最长的成员所占的存储空间; 2.若是该最长的存储空间对其他成员的元类型 (如果是数组 ,取其类型的数据长度 ,例 int a5为 4)不满足 整除关系 ,该最大空间自动延伸 ; 我们来看看这段代码 : union mm char a;/元长度 1 int b5;/元长度 4 double c;/元长度 8 int d3; ; 本来 mm 的空间应该 是 sizeof(int)*5=20;但是如。

14、果只是 20 个单元的话 ,那可以存几个 double 型 (8 位 )呢 ?两 个半 ?当然不可以 ,所以 mm 的空间延伸为既要大于 20,又要满足其他成员所需空间的整数倍 ,即 24 所以 union 的存储空间先看它的成员中哪个占的空间最大 ,拿他与其他成员的元长度比较 ,如果可以整除就 行 。 九、指定对界 #pragma pack()命令 如何修改编译器的默认对齐值 ? 1.在 VC IDE 中,可以这样修改: Project|Settings,c/c+选项卡 Category的 Code Generation 选项的 Struct Member Alignment 中修改,默认是。

15、 8 字节。 2.在编码时,可以这样动态修改: #pragma pack .注意 :是 pragma 而不是 progma. 一般地,可以通过下面的方法来改变缺省的对界条件: 使用伪指令 #pragma pack (n),编译器将按照 n 个字节对齐; 使用伪指令 #pragma pack (),取消自定义字节对齐方式。 注意:如果 #pragma pack (n)中指定的 n 大于结构体中最大成员 size,则其不起作用,结构体仍然按照 size 最大的成员进行对界。 为了节省空间,我们可以在编码时通过 #pragma pack()命令指定程序的对齐方式,括号中是对齐的字节数, 若该命令括号。

16、中的内容为空,则为默认对齐方式。例如,对于上面第一个结构体,如果通过该命令手动设 置对齐字节数如下: #pragma pack(2) /设置 2 字节对齐 struct strdent char name5; /本身 1 字节对齐,比 2 字节对齐小,按 1 字节对齐 int num; /本身 4 字节对齐,比 2 字节对齐大,按 2 字节对齐 short score; /本身也 2 字节对齐,仍然按 2 字节对齐 #pragma pack() / 恢复先前的 pack 设置 ,取消设置的字节对齐方式 则, num 从第 6(偏移量)个字节开始存放, score 从第 10(偏移量)个字节开始。

17、存放,故 sizeof(student)=12, 其数据对齐如下图: |char|char| |char|char| |char|-| |-int-| |-int-| |-short-| 这样改变默认的字节对齐方式可以更充分地利用存储空间,但是这会降低计算机读写数据的速度,是一种 以时间换取空间的方式。 十、代码验证 代码 /- / 环境: VS2005 / 时间: 2010.9.24 / 用途:结构体大小测试 / 作者: /- #include “stdafx.h“ #include using namespace std; /空 struct S0 ; struct S1 char a;。

18、 long b; ; struct S2 long b; char a; ; struct S3 char c; struct S1 d;/结构体 long e; ; struct S4 char a; long b; static long c; /静态 ; struct S5 char a; long b; char name5; /数组 ; /含有一个数组 struct S6 char a; long b; int name5; /数组 ; struct student0 char name5; int num; short score; ; struct student1 int nu。

19、m; char name5; short score; ; struct student2 int num; short score; char name5; ; union union1 long a; double b; char name9; ; union union2 char a; int b5; double c; int d3; ; int main(int argc, char* argv) cout “char: “ sizeof(char) endl; /1 cout “long: “ sizeof(long) endl; /4 cout “int: “ sizeof(i。

20、nt) endl; /4 cout “S0: “ sizeof(S0) endl; /1 cout “S1: “ sizeof(S1) endl; /8 cout “S2: “ sizeof(S2) endl; /8 cout “S3: “ sizeof(S3) endl; /24 cout “S4: “ sizeof(S4) endl; /8 cout “S5: “ sizeof(S5) endl; /16 cout “S6: “ sizeof(S6) endl; /28 cout “union1 :“ sizeof(union1) endl; cout “union2 :“ sizeof(。

21、union2) endl; cout “student0: “ sizeof(student0) endl; cout “student1: “ sizeof(student1) endl; cout “student2: “ sizeof(student2) endl; system(“pause“); return 0; 输出 /这是默认的结果 ( 8 字节对齐) char: 1 long: 4 int: 4 S0: 1 S1: 8 S2: 8 S3: 16 S4: 8 S5: 16 S6: 28 union1 :16 union2 :24 student0: 16 student1: 1。

22、2 student2: 12 请按任意键继续 . . . /这是 16 字节对齐的结果,可以看到当设置 16 字节对齐时,确实没什么效果,里面最大的是 double,也 就是 8 字节, #pragma pack (n)中指定的 n 大于结构体中最大成员 size,则其不起作用。 char: 1 long: 4 int: 4 double:8 S0: 1 S1: 8 S2: 8 S3: 16 S4: 8 S5: 16 S6: 28 union1 :16 union2 :24 student0: 16 student1: 12 student2: 12 请按任意键继续 . . . /这是 2 字。

23、节对齐的结果,可以慢慢参考研究 char: 1 long: 4 int: 4 double:8 S0: 1 S1: 6 S2: 6 S3: 12 S4: 6 S5: 12 S6: 26 union1 :10 union2 :20 student0: 12 student1: 12 student2: 12 请按任意键继续 . . . 说明: ( 1)默认 8 字节对齐 ( 2)分析 S0:空 S1: |char|-|-|-| |-long-| S2: |-long-| |char|-|-|-| S3: 其中包含的 S1 中最长的为 long, S3 中也为 long,以最长的为分界,那么为: 。

24、1+8+4 = 13,那么这个结构 体的长度就是 8 的倍数 16。 内存是怎么样的现在还没有弄清楚。 S4: 静态变量存放在全局数据区内,而 sizeof 计算栈中分配的空间的大小,故不计算在内, S4 的大小为 4+4=8。 S5, S6, Student 见上面例子。 union1: 最长 double=8,但 char c9用 9 个不够,再加一倍到 16. union2: 类型最长的是 long=8,变量最长的是 int b5 = 4*5=20, 20 以上 8 的倍数为 24。 十一、还没有解决的问题 虽然知道结构体中含有结构体的长度怎么计算,但不知道它的内存是什么样子的,在 VS。

25、 中用 cout “ 为什么显示出来是乱码? 十二、字节对齐可能带来的隐患 (说明:从一个 pdf 复制,参考一下) 代码中关于对齐的隐患,很多是隐式的。比如在强制类型转换的时候。例如: unsigned int i = 0x12345678; unsigned char *p=NULL; unsigned short *p1=NULL; p= *p=0x00; p1=(unsigned short *)(p+1); *p1=0x0000; 最后两句代码,从奇数边界去访问 unsignedshort 型变量,显然不符合对齐的规定。 在 x86 上,类似的操作只会影响效率,但是在 MIPS 或者 sparc 上,可能就是一个 error,因为它们要求必须 字节对齐。 十三、参考引用 在上述内容中,引用参考了不少文章,现将链接给出,同时感谢 Scorpions 带来的音乐快感。这里仅供本 人学习,谢谢作者。 http:/ http:/ http:/ http:/ http:/ http:/ http:/ 本文章出 处: http:/ 。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3