结构体对齐规则及举例

  • 结构体概念
  • 结构体声明
  • 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++中的字节对齐

结构体的对齐规则及举例相关推荐

  1. C语言结构体字节对齐规则

    C语言结构体字节对齐规则 基本规则 规则1 :结构体(struct)的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存放在offset为该数据成员大小的整数倍的地方(比如int在 ...

  2. 整数边界对齐方式_c中结构体边界对齐(转)

    c中结构体边界对齐(转) 2011-11-23 11:15:52|  分类: C&C++ |  标签: |字号大中小 C语言结构体对齐也是老生常谈的话题了.基本上是面试题的必考题.结构体到底怎 ...

  3. c语言结构体的对齐方式,C语言结构体内存的对齐知识详解

    前言 在前面的章节中,我们谈到了C语言中整数以及浮点数的储存 今天,我们来谈一谈一些关于结构体内存的知识. 我们先来看一个例子: struct S1 { char c1; int i; char c2 ...

  4. 结构体(对齐规则及举例)

    结构体(对齐规则及举例) 文章目录 结构体(对齐规则及举例) 概念 结构体声明 结构体对齐规则 对齐原因 对齐规则 举例说明对齐原则 C++中的结构体struct------类 class和struc ...

  5. 【C语言】一文搞定如何计算结构体的大小----结构体内存对齐规则

    要搞定如何正确地计算一个结构体的大小,我们就要深刻理解结构体内存对齐规则: 结构体内存对齐规则: 1.结构体的第一个成员永远在结构体起始位置偏移量为0的位置: 2.结构体成员从第二个成员开始,总是放在 ...

  6. 结构体字节对齐详解【含实例】

    一.前言 结构体字节对齐属于老生常谈的问题,看似简单,却很容易忘记.而且因为结构体使用的普遍性,使得字节对齐也成为了一个不得不谈的话题. 二.什么是结构体字节对齐 假设现在有一个结构体如下,问你它的一 ...

  7. 结构体字节对齐(转)

    结构体字节对齐 在用sizeof运算符求算某结构体所占空间时,并不是简单地将结构体中所有元素各自占的空间相加,这里涉及到内存字节对齐的问题.从理论上讲,对于任何变量的访问都可以从任何地址开始访问,但是 ...

  8. 指定结构体字节对齐方式

    指定结构体字节对齐方式 #pragma pack(push,1) typedef struct  { int b; char a;  }struct_t1; #pragma pack(pop)

  9. 一文了解结构体字节对齐

    结构体字节对齐详解 表述如有不正确的地方,欢迎批评指正. C++/C 常见的基本数据类型: bool short (short int) int long (long int) long long ( ...

最新文章

  1. No changes detected
  2. iOS之Socket的使用-AsyncSocket
  3. iview 下拉select样式_Vue.js相关:iview实现select tree树形下拉框的示例代码
  4. Java 8 Friday:大多数内部DSL已过时
  5. Python 学习笔记 - 作用域小知识
  6. element表格固定某一行_elementui 表格 固定列+合计行
  7. 如何使用.NET清除IE的缓存(Temporary Internet Files)
  8. 服务器添加hdr文件3dMax,别再乱用HDR了!关于它的10件事你该知道
  9. 语音信号预加重与去加重(Matlab+Keil)
  10. [信息论与编码理论专题-6]:物理层信道编码
  11. w ndows键是哪一个,Win10截图快捷键是哪个?Windows10自带截屏快捷键使用方法大全...
  12. tplink查看上网记录_Tplink路由器PPPOE拨号不能上网日志查看原因
  13. 输入一个大写字母,打印菱形
  14. 网络基础 — IP地址和子网掩码
  15. AI智能联系人管理系统(一)
  16. 如何去除图片中的白色背景(变透明)
  17. 【计算方法数值分析】复化梯形公式、复化辛普森公式和龙贝格数值积分
  18. 大学生生涯规划1000字计算机专业,我的职业生涯规划计算机专业1000字
  19. 小程序开发--- 1. 获取数组中某个字段的值或获取列表索引
  20. dg的奇怪问题终结和分区问题答疑 (r7笔记第77天)

热门文章

  1. Windows账户设置
  2. STM32使用模拟I2C读取AS5600(深入讲解:带波形图)
  3. 8、半导体二极管的伏安特性和电流方程
  4. 重启docker(docker卡住的时候)
  5. 我准备这样在B站快速学习Java!附上B站视频链接以及白嫖视频教程
  6. 多人同时连接一个数据库——非常简单
  7. 基于Python的OpenCV人脸检测
  8. Java扫描二维码进行会议签到思路
  9. buu-[羊城杯 2020]easyre
  10. 用千千静听修改mp3乱码