1分钟了解C语言正确使用字节对齐及#pragma pack的方法

​  C/C++编译器的缺省字节对齐方式为自然对界。即在缺省情况下,编译器为每一个变量或是数据单元按其自然对界条件分配空间。

  在结构中,编译器为结构的每个成员按其自然对界(alignment)条件分配空间。各个成员按照它们被声明的顺序在内存中顺序存储(成员之间可能有插入的空字节),第一个成员的地址和整个结构的地址相同。

  编译器缺省的结构成员自然对界条件为“N字节对齐”,N即该成员数据类型的长度。如int型成员的自然对界条件为4字节对齐,而double类型的结构成员的自然对界条件为8字节对齐。若该成员的起始偏移不位于该成员的“默认自然对界条件”上,则在前一个节面后面添加适当个数的空字节。

        编译器缺省的结构整体的自然对界条件为:该结构所有成员中要求的最大自然对界条件。若结构体各成员长度之和不为“结构整体自然对界条件的整数倍”,则在最后一个成员后填充空字节。

        例子1(分析结构各成员的默认字节对界条界条件和结构整体的默认字节对界条件):

1 struct Test
2 { 
3   char x1; // 成员x1为char型(其起始地址必须1字节对界),其偏移地址为0 
4   char x2; // 成员x2为char型(其起始地址必须1字节对界,其偏移地址为1 
5   float x3; // 成员x3为float型(其起始地址必须4字节对界),编译器在x2和x3之间填充了两个空字节,其偏移地址为4 
6   char x4; // 成员x4为char型(其起始地址必须1字节对界),其偏移地址为8 
7 };

1分钟了解C语言正确使用字节对齐及#pragma pack的方法

        在Test结构体中,最大的成员为float x3,因此结构体的自然对界条件为4字节对齐。则结构体长度就为12字节,内存布局为1100 1111 1000。

 1 #include <stdio.h>
 2 typedef struct
 3 {
 4   int aa1; //4个字节对齐 1111
 5   char bb1;//1个字节对齐 1
 6   short cc1;//2个字节对齐 011
 7   char dd1; //1个字节对齐 1
 8 } testlength1;
 9 int length1 = sizeof(testlength1); //4个字节对齐,占用字节1111 1011 1000,length = 12
10 
11 typedef struct
12 {
13   char bb2;//1个字节对齐 1
14   int aa2; //4个字节对齐 01111
15   short cc2;//2个字节对齐 11
16   char dd2; //1个字节对齐 1
17 } testlength2;
18 int length2 = sizeof(testlength2); //4个字节对齐,占用字节1011  1111 1000,length = 12
19 
20 typedef struct
21 {
22   char bb3; //1个字节对齐 1
23   char dd3; //1个字节对齐 1
24   int aa3; //4个字节对齐 001111
25   short cc23//2个字节对齐 11
26 
27 } testlength3;
28 int length3 = sizeof(testlength3); //4个字节对齐,占用字节1100 1111 1100,length = 12
29 
30 typedef struct
31 {
32   char bb4; //1个字节对齐 1
33   char dd4; //1个字节对齐 1
34   short cc4;//2个字节对齐 11
35   int aa4; //4个字节对齐 1111
36 } testlength4;
37 int length4 = sizeof(testlength4); //4个字节对齐,占用字节1111 1111,length = 8
38 
39 int main(void)
40 {
41   printf("length1 = %d.\n",length1);
42   printf("length2 = %d.\n",length2);
43   printf("length3 = %d.\n",length3);
44   printf("length4 = %d.\n",length4);
45   return 0;
46 }

        改变缺省的对界条件(指定对界)
· 使用伪指令#pragma pack (n),编译器将按照n个字节对齐。

· 使用伪指令#pragma pack (),取消自定义字节对齐方式。

        这时,对齐规则为:

        1、数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。

        2、结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。

        结合1、2推断:当#pragma pack的n值等于或超过所有数据成员长度的时候,这个n值的大小将不产生任何效果。

        因此,当使用伪指令#pragma pack (2)时,Test结构体的大小为8,内存布局为11 11 11 10。

        需要注意一点,当结构体中包含一个子结构体时,子结构中的成员按照#pragma pack指定的数值和子结构最大数据成员长度中,比较小的那个进行进行对齐。例子如下:

 1 #pragma pack(8)
 2 struct s1
 3 {
 4   short a;
 5   long b;
 6 };
 7 
 8 struct s2
 9 {
10   char c;
11   s1 d;
12   long long e;
13 };
14 #pragma pack()

        sizeof(s2)的结果为24。S1的内存布局为1100 1111,S2的内存布局为1000 1100 1111 0000 1111 1111。

        例子2按照2个字节对齐时:

 1 #include <stdio.h>
 2 #pragma pack(2)
 3 typedef struct
 4 {
 5   int aa1; //2个字节对齐 1111
 6   char bb1;//1个字节对齐 1
 7   short cc1;//2个字节对齐 011
 8   char dd1; //1个字节对齐 1
 9 } testlength1;
10 int length1 = sizeof(testlength1); //2个字节对齐,占用字节11 11 10 11 10,length = 10
11 
12 typedef struct
13 {
14   char bb2;//1个字节对齐 1
15   int aa2; //2个字节对齐 01111
16   short cc2;//2个字节对齐 11
17   char dd2; //1个字节对齐 1
18 } testlength2;
19 int length2 = sizeof(testlength2); //2个字节对齐,占用字节10 11 11 11 10,length = 10
20 
21 typedef struct
22 {
23   char bb3; //1个字节对齐 1
24   char dd3; //1个字节对齐 1
25   int aa3; //2个字节对齐 11 11
26   short cc23//2个字节对齐 11
27 
28 } testlength3;
29 int length3 = sizeof(testlength3); //2个字节对齐,占用字节11 11 11 11,length = 8
30 
31 typedef struct
32 {
33   char bb4; //1个字节对齐 1
34   char dd4; //1个字节对齐 1
35   short cc4;//2个字节对齐 11
36   int aa4; //2个字节对齐 11 11
37 } testlength4;
38 int length4 = sizeof(testlength4); //2个字节对齐,占用字节11 11 11 11,length = 8
39 #pragma pack()
40 int main(void)
41 {
42   printf("length1 = %d.\n",length1);
43   printf("length2 = %d.\n",length2);
44   printf("length3 = %d.\n",length3);
45   printf("length4 = %d.\n",length4);
46   return 0;
47 }

1分钟了解C语言正确使用字节对齐及#pragma pack的方法

        另外,还有如下的一种方式:

        · __attribute((aligned (n))),让所作用的结构成员对齐在n字节自然边界上。如果结构中有成员的长度大于n,则按照最大成员的长度来对齐。

        · __attribute__ ((packed)),取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐。

       以上的n = 1, 2, 4, 8, 16... 第一种方式较为常见。


↓↓↓更多技术内容和书籍资料获取,入群技术交流敬请关注“明解嵌入式”↓↓↓ 

1分钟了解C语言正确使用字节对齐及#pragma pack的方法

 

原文链接:https://www.cnblogs.com/Sharemaker/p/17375352.html

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:1分钟了解C语言正确使用字节对齐及#pragma pack的方法 - Python技术站

(0)
上一篇 2023年4月30日
下一篇 2023年5月9日

相关文章

  • 详解javascript对数组和json数组的操作

    下面是详解 JavaScript 对数组和 JSON 数组的操作的完整攻略。 JavaScript 数组操作 声明和初始化数组 JavaScript 中声明和初始化一个数组可以使用以下方式: // 声明空数组 var arr = []; // 声明同时初始化数组 var arr = [1, 2, 3]; // 使用 Array 构造函数声明和初始化数组 va…

    C 2023年5月23日
    00
  • 比特币账本存在哪里?比特币账本是谁在记账?

    比特币是一种去中心化的加密货币,其账本被称为区块链,所有的交易记录都会被记录在这个分布式账本上。在比特币网络中,没有一个具体的机构或个人承担记账的角色,而是由所有参与的矿工通过计算机算力获得区块链账本更新的权利,并依次将记录的新交易打包成新的区块,并将其添加到链的尾部,为整个系统提供保障。 具体来说,比特币的记账过程是由矿工通过一系列计算机算法竞争产生的,其…

    C 2023年5月22日
    00
  • JavaScript数组,JSON对象实现动态添加、修改、删除功能示例

    下面是详细的攻略: 简介 在网页开发过程中,经常需要处理数据。JavaScript中的数组和JSON对象是最常用的数据结构,在实际开发中,需要对数组和JSON对象进行动态添加、修改、删除等操作。本文将详细介绍如何使用JavaScript实现这些操作。 数组 动态添加元素 使用push()方法可以向数组末尾添加一个或多个元素,使用unshift()方法可以向数…

    C 2023年5月23日
    00
  • PHPExcel简单读取excel文件示例

    当我们需要读取excel文件中的数据时,我们可以使用PHPExcel库。下面将详细讲解“PHPExcel简单读取excel文件示例”的完整攻略。 准备 首先需要在项目中引入PHPExcel库,可以使用Composer安装,也可以手动下载和引入。 示例1 下面是一个最简单的读取excel文件第一个工作表中所有数据的示例代码: // 引入PHPExcel req…

    C 2023年5月23日
    00
  • Excel如何使用组合函数combin

    Excel如何使用组合函数COMBIN comibn函数的作用 COMBIN函数用于计算从一组n个元素中选择r个元素的组合数。其数学公式为: COMBIN(n, r) = n!/((n-r)!*r!) 其中, n为总元素数,r为选中元素数. COMBIN函数的使用方法 COMBIN函数的语法为: COMBIN(number, number_chosen) 参…

    C 2023年5月22日
    00
  • C语言比较字符串

    下面是详细讲解“C语言比较字符串”的完整使用攻略。 为什么需要比较字符串? 在程序中,需要对字符串进行比较的场景很常见。例如,能否登录的用户名和密码的验证,输入文本框中输入的内容是否符合要求等等。因此,字符串的比较是基础中的基础,是开发者必须熟练掌握的技能之一。 字符串比较的基本概念 C语言中,有一系列函数用于字符串比较。 我们先来认识一下这些函数: str…

    C 2023年5月9日
    00
  • C语言实现最小生成树构造算法

    C语言实现最小生成树构造算法攻略 最小生成树(Minimum Spanning Tree,MST)是一种求加权无向连通图的生成树的算法,其可以将连通图的n个顶点连接起来,形成一个权值最小的树。本文将介绍使用C语言实现最小生成树构造算法的攻略。 算法简介 其中,Kruskal算法和Prim算法是最常用的两个求解最小生成树的算法。 Kruskal算法 Krusk…

    C 2023年5月22日
    00
  • vs怎么实现C语言的按位左移运算程序?

    实现C语言中的按位左移运算程序可以通过使用位操作符 << 实现,具体步骤如下: 定义两个变量 num 和 shift,num 为需要左移的数,shift 为需要左移的位数。 使用 << 位操作符将 num 左移 shift 位,即将 num 的二进制表示左移 shift 位,如 num << shift。 下面是两个示例代…

    C 2023年5月23日
    00
合作推广
合作推广
分享本页
返回顶部