结构体的对齐规则及举例
结构体对齐规则及举例
- 结构体概念
- 结构体声明
- C语言中char、short、int、long各占多少字节
- C语言中编译器字节对齐
- 自然对齐
- 字节对齐
- 为什么要字节对齐
- 正确处理字节对齐
- __attribute__选项
- 什么时候需要设置对齐
- 更改C编译器的缺省字节对齐方式
- 结构体对齐规则
- C++中的结构体struct---类
结构体概念
- 一种数据结构;
- C语言中聚合数据类型的一类;
- 可以被声明为变量、数组、指针等,用以实现比较复杂的数据结构;
- 是一系列元素的集合,这些元素被称为结构体成员;
- 结构体成员需要用结构体名访问。
结构体声明
struct A{ //struct是关键字, A是结构体标志int a; //a,b是结构体成员列表char b;
}s1; //s1是结构体变量
注意事项:
- 一般情况下,声明出现三个部分的两个部分即可(标志或者变量可省略)
- 结构体可以包含其他结构体,也可以包含指向自己的指针
- 结构体互相包含时,需要对其中一个进行不完整声明
C语言中char、short、int、long各占多少字节
编程语言上的32位与64位差异主要体现在基本类型的位长上。C/C++等语言仅仅定义了这些基本数据类型之间的关系,并没有严格定义它们的字长。不同操作系统平台上存在不同。注意占据的字节数跟操作系统没有关系,跟使用的编译器有关,和编译器的数据模型相关
其中,LP64,ILP64,LLP64是64位平台上的字长模型,ILP32和LP32是32位平台上的字长模型。LP64指long和pointer是64位,ILP64指int、long和pointer是64位,LLP64指long long和pointer是64位,ILP32指int、long和pointer是32位,LP32指long和pointer是32位的。
32位windows采用的是ILP32数据模型,64位windows采用的是LLP64数据模型,32位Linux采用的是ILP32模型,64位Unix / Linux使用的是LP64模型。
在标准C中规定,长整型(无论无符号或者有符号)至少占用32位,标准没有规定 long 长度,这是编译器和系统选择的。在OS的ABI中应当有数据类型大小的定义。
以下引自维基 64位数据模型
- 在32位程序中,指针和数据类型(例如整数)通常具有相同的长度。在64位计算机上不一定是这样。因此,在C等编程语言及其后代(例如C ++和Objective-C )中混合数据类型可能适用于32位实现,但不适用于64位实现。
- 在许多用于64位计算机上C和C派生语言的编程环境中,int变量仍然是32位宽,但是长整数和指针是64位宽。这些被描述为具有LP64 数据模型。另一个替代方法是ILP64数据模型,其中所有三种数据类型均为64位宽,甚至是短整数也为64位宽的SILP64。但是,在大多数情况下,所需的修改相对较小且简单明了,许多编写良好的程序可以简单地为新环境重新编译而无需更改。另一种替代方法是LLP64模型,它通过使两个保持与32位代码的兼容性int和long为32位。LL指的是long long整数类型,在包括32位环境在内的所有平台上至少为64位。
数据类型转换原则
C语言中编译器字节对齐
自然对齐
对齐跟数据在内存中的位置有关。如果一个变量的内存地址正好位于它长度的整数倍,他就被称做自然对齐。比如在32位cpu下,假设一个整型变量的地址为0x00000004,那它就是自然对齐的。
字节对齐
在C语言中,结构是一种复合数据类型,其构成元素既可以是基本数据类型(如int、long、float等)的变量,也可以是一些复合数据类型(如数组、结构、联合等)的数据单元。在结构中,编译器为结构的每个成员按其自然边(alignment)分配空间。各个成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构的地址相同。为了使CPU能够对变量进行快速的访问,变量的起始地址应该具有某些特性,即所谓的”对齐”.
为什么要字节对齐
需要字节对齐的根本原因在于CPU访问数据的效率问题。假设上面整型变量的地址不是自然对齐,比如为0x00000002,则CPU如果取它的值的话需要访问两次内存,第一次取从0x00000002-0x00000003的一个short,第二次取从0x00000004-0x00000005的一个short然后组合得到所要的数据,如果变量在0x00000003地址上的话则要访问三次内存,第一次为char,第二次为short,第三次为char,然后组合得到整型数据。而如果变量在自然对齐位置上,则只要一次就可以取出数据。一些系统对对齐要求非常严格,比如sparc系统,如果取未对齐的数据会发生错误,举个例:
char ch[8];char *p = &ch[1];int i = *(int *)p;
运行时会报segment error,而在x86上就不会出现错误,只是效率下降。
正确处理字节对齐
对于标准数据类型,它的地址只要是它的长度的整数倍就行了,而非标准数据类型按下面的原则对齐:
数组 :按照基本数据类型对齐,第一个对齐了后面的自然也就对齐了。
联合 :按其包含的长度最大的数据类型对齐。
结构体: 结构体中每个数据类型都要对齐。
比如有如下一个结构体:
struct stu
{char sex;int length;char name[10];
};
struct stu my_stu;
由于在x86下,GCC默认按4字节对齐,它会在sex后面跟name后面分别填充三个和两个字节使length和整个结构体对齐。于是我sizeof(my_stu)会得到长度为20,而不是15.
__attribute__选项
我们可以按照自己设定的对齐大小来编译程序,GNU使用__attribute__选项来设置,比如我们想让刚才的结构按一字节对齐,我们可以这样定义结构体
struct stu
{char sex;int length;char name[10];
}attribute ((aligned (1)));struct stu my_stu;
则sizeof(my_stu)可以得到大小为15。上面的定义等同于
struct stu
{char sex;int length;char name[10];
}attribute ((packed));struct stu my_stu;
attribute((packed))得变量或者结构体成员使用最小的对齐方式,即对变量是一字节对齐,对域(field)是位对齐.
什么时候需要设置对齐
1.在设计不同CPU下的通信协议;
2.编写硬件驱动程序时寄存器的结构这两个地方都需要按一字节对齐;
3.文件系统中数据存储(项目代码中使用的原因)
更改C编译器的缺省字节对齐方式
在缺省情况下,C编译器为每一个变量或是数据单元按其自然对界条件分配空间。一般地,可以通过下面的方法来改变缺省的对界条件:
- 使用伪指令#pragma pack (n),C编译器将按照n个字节对齐。
- 使用伪指令#pragma pack (),取消自定义字节对齐方式。
另外,还有如下的一种方式:
- attribute((aligned (n))),让所作用的结构成员对齐在n字节自然边界上。如果结构中有成员的长度大于n,则按照最大成员的长度来对齐。
- attribute ((packed)),取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐。
结构体对齐规则
- 计算结构体大小不是元素单纯相加;
- 32位CPU取四个字节比一个字节更高效方便;
- 若每个元素首地址都是4的整数倍,取数据元素就能更高效方便;
- 每个特定平台上编译器都有自己的默认的对齐系数(对齐模数),可通过编译命令来改变这一系数;
- #pragma pack(n);//n=1,2,4,8,16,其中n就是你想要指定的系数。
- 一般情况下32位默认4字节对齐。
对齐原因
- 平台原因(移植原因)
不是所有的硬件平台都能访问任意地址的任意数据,某些硬件平台只能在某些地址处取某些特定类型的数据的,否则抛出硬件异常。 - 性能原因
数据结构(尤其是栈),应该尽可能在自然边界上对齐,因为在访问为对齐的内存时,处理器需要访问两次,而对齐的内存处理器只需要访问一次。
对齐规则
- 第一个成员在与结构体变量偏移量(offset)为0的地址处。
- 其他成员变量要对齐到对齐数的整数倍的地址处。
- 对齐数 = 对齐系数 与 该成员大小的较小值。
- #pragma pack(n);中的n就是对齐系数。
- VS中默认的值为8;linux中的默认值为4。
- 结构体总大小为最大对齐数(每个成员变量除了第一个成员都有一个对齐数)的整数倍。
- 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
举例说明对齐原则
1.下面的结构体大小分别是多大(假设32位机器)?
struct A {char a; //1
char b; //1
char c; //1
};
//进行整体对齐,最大类型为1<对齐系数4,按1整体对齐,所以1+1+1=3
struct B {int a; //4
char b; //1
short c;//2
};
//进行整体对齐,最大类型为4=对齐系数4,所以按4整体对齐4 1+2=3<4 对齐4 所以4+4=8
struct C {char b; //1
int a; //4
short c;//2
};
//进行整体对齐,最大类型为4=对齐系数4,所以按4整体对齐 1<4(对齐4) 4=4 2<4(对齐4) 所以4+4+4=12
#pragma pack(2)
struct D {char b; //1
int a; //4
short c;//2
};
//进行整体对齐,最大类型为4>对齐系数n(2),所以按2整体对齐 1<2(对齐2)4>2(2的倍数) 2=2 所以2+4+2=8
答案及解析:3 8 12 82. 有一个如下的结构体:
struct A{long a1;short a2;int a3;int *a4;
};
请问在64位编译器下用sizeof(struct A)计算出的大小是多少?
24
28
16
18答案及解析:24
64位编译器下:指针8字节(一定不能忘记),题目不说默认4字节对齐
long a1; //8short a2; //2 8+2=10(不是4的倍数)对齐到4的倍数12int a3; //4 4+12=16(4的倍数)int *a4; //8 8+16=24(4的倍数)3.在32位cpu上选择缺省对齐的情况下,有如下结构体定义:
struct A{unsigned a : 19;unsigned b : 11;unsigned c : 4;unsigned d : 29;char index;
};
则sizeof(struct A)的值为()
9
12
16
20
答案及解析16
题目不说,默认4字节对齐
19+11=30<32bit 4
4+29=33>32bit 4+4
1byte=8bit 1 对齐到 4
4+4+4+4=16
C++中的结构体struct—类
- 在C++中struct是对于C语言中struct的扩展,因为C++是面向对象的语言,可以描述对象的行为,所以在C++中struct内可以放函数,从而就具有类的功能,但又和class有一定的区别。
class和struct的区别
- class默认成员是私有的private,struct默认成员是公有的public
- class继承默认是私有的private,struct继承默认是公有的public
- C++中结构体可以不要struct关键字,C语言中除了typedef定义别名之外是必须要struct关键字。
参考:https://www.cnblogs.com/wsq-888/p/jie-gou-ti-dui-qi-gui-ze-ji-ju-li.html
更多阅读:面试常考,项目易错,长文详解C/C++中的字节对齐
结构体的对齐规则及举例相关推荐
- C语言结构体字节对齐规则
C语言结构体字节对齐规则 基本规则 规则1 :结构体(struct)的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存放在offset为该数据成员大小的整数倍的地方(比如int在 ...
- 整数边界对齐方式_c中结构体边界对齐(转)
c中结构体边界对齐(转) 2011-11-23 11:15:52| 分类: C&C++ | 标签: |字号大中小 C语言结构体对齐也是老生常谈的话题了.基本上是面试题的必考题.结构体到底怎 ...
- c语言结构体的对齐方式,C语言结构体内存的对齐知识详解
前言 在前面的章节中,我们谈到了C语言中整数以及浮点数的储存 今天,我们来谈一谈一些关于结构体内存的知识. 我们先来看一个例子: struct S1 { char c1; int i; char c2 ...
- 结构体(对齐规则及举例)
结构体(对齐规则及举例) 文章目录 结构体(对齐规则及举例) 概念 结构体声明 结构体对齐规则 对齐原因 对齐规则 举例说明对齐原则 C++中的结构体struct------类 class和struc ...
- 【C语言】一文搞定如何计算结构体的大小----结构体内存对齐规则
要搞定如何正确地计算一个结构体的大小,我们就要深刻理解结构体内存对齐规则: 结构体内存对齐规则: 1.结构体的第一个成员永远在结构体起始位置偏移量为0的位置: 2.结构体成员从第二个成员开始,总是放在 ...
- 结构体字节对齐详解【含实例】
一.前言 结构体字节对齐属于老生常谈的问题,看似简单,却很容易忘记.而且因为结构体使用的普遍性,使得字节对齐也成为了一个不得不谈的话题. 二.什么是结构体字节对齐 假设现在有一个结构体如下,问你它的一 ...
- 结构体字节对齐(转)
结构体字节对齐 在用sizeof运算符求算某结构体所占空间时,并不是简单地将结构体中所有元素各自占的空间相加,这里涉及到内存字节对齐的问题.从理论上讲,对于任何变量的访问都可以从任何地址开始访问,但是 ...
- 指定结构体字节对齐方式
指定结构体字节对齐方式 #pragma pack(push,1) typedef struct { int b; char a; }struct_t1; #pragma pack(pop)
- 一文了解结构体字节对齐
结构体字节对齐详解 表述如有不正确的地方,欢迎批评指正. C++/C 常见的基本数据类型: bool short (short int) int long (long int) long long ( ...
最新文章
- No changes detected
- iOS之Socket的使用-AsyncSocket
- iview 下拉select样式_Vue.js相关:iview实现select tree树形下拉框的示例代码
- Java 8 Friday:大多数内部DSL已过时
- Python 学习笔记 - 作用域小知识
- element表格固定某一行_elementui 表格 固定列+合计行
- 如何使用.NET清除IE的缓存(Temporary Internet Files)
- 服务器添加hdr文件3dMax,别再乱用HDR了!关于它的10件事你该知道
- 语音信号预加重与去加重(Matlab+Keil)
- [信息论与编码理论专题-6]:物理层信道编码
- w ndows键是哪一个,Win10截图快捷键是哪个?Windows10自带截屏快捷键使用方法大全...
- tplink查看上网记录_Tplink路由器PPPOE拨号不能上网日志查看原因
- 输入一个大写字母,打印菱形
- 网络基础 — IP地址和子网掩码
- AI智能联系人管理系统(一)
- 如何去除图片中的白色背景(变透明)
- 【计算方法数值分析】复化梯形公式、复化辛普森公式和龙贝格数值积分
- 大学生生涯规划1000字计算机专业,我的职业生涯规划计算机专业1000字
- 小程序开发--- 1. 获取数组中某个字段的值或获取列表索引
- dg的奇怪问题终结和分区问题答疑 (r7笔记第77天)