0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

C/C++编译器的缺省字节对齐方式

CHANBAEK 来源:明解嵌入式 作者:Sharemaker001 2023-04-15 11:24 次阅读

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

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

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

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

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

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

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

例子2:

#include 
typedef struct
{
  int aa1; //4个字节对齐 1111
  char bb1;//1个字节对齐 1
  short cc1;//2个字节对齐 011
  char dd1; //1个字节对齐 1
} testlength1;
int length1 = sizeof(testlength1); //4个字节对齐,占用字节1111 1011 1000,length = 12


typedef struct
{
  char bb2;//1个字节对齐 1
  int aa2; //4个字节对齐 01111
  short cc2;//2个字节对齐 11
  char dd2; //1个字节对齐 1
} testlength2;
int length2 = sizeof(testlength2); //4个字节对齐,占用字节1011  1111 1000,length = 12


typedef struct
{
  char bb3; //1个字节对齐 1
  char dd3; //1个字节对齐 1
  int aa3; //4个字节对齐 001111
  short cc23//2个字节对齐 11


} testlength3;
int length3 = sizeof(testlength3); //4个字节对齐,占用字节1100 1111 1100,length = 12


typedef struct
{
  char bb4; //1个字节对齐 1
  char dd4; //1个字节对齐 1
  short cc4;//2个字节对齐 11
  int aa4; //4个字节对齐 1111
} testlength4;
int length4 = sizeof(testlength4); //4个字节对齐,占用字节1111 1111,length = 8


int main(void)
{
  printf("length1 = %d.\\n",length1);
  printf("length2 = %d.\\n",length2);
  printf("length3 = %d.\\n",length3);
  printf("length4 = %d.\\n",length4);
  return 0;
}

改变缺省的对界条件(指定对界)

· 使用伪指令#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指定的数值和子结构最大数据成员长度中,比较小的那个进行进行对齐。 例子如下:

#pragma pack(8)
struct s1
{
  short a;
  long b;
};


struct s2
{
  char c;
  s1 d;
  long long e;
};
#pragma pack()

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

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

#include 
#pragma pack(2)
typedef struct
{
  int aa1; //2个字节对齐 1111
  char bb1;//1个字节对齐 1
  short cc1;//2个字节对齐 011
  char dd1; //1个字节对齐 1
} testlength1;
int length1 = sizeof(testlength1); //2个字节对齐,占用字节11 11 10 11 10,length = 10


typedef struct
{
  char bb2;//1个字节对齐 1
  int aa2; //2个字节对齐 01111
  short cc2;//2个字节对齐 11
  char dd2; //1个字节对齐 1
} testlength2;
int length2 = sizeof(testlength2); //2个字节对齐,占用字节10 11 11 11 10,length = 10


typedef struct
{
  char bb3; //1个字节对齐 1
  char dd3; //1个字节对齐 1
  int aa3; //2个字节对齐 11 11
  short cc23//2个字节对齐 11


} testlength3;
int length3 = sizeof(testlength3); //2个字节对齐,占用字节11 11 11 11,length = 8


typedef struct
{
  char bb4; //1个字节对齐 1
  char dd4; //1个字节对齐 1
  short cc4;//2个字节对齐 11
  int aa4; //2个字节对齐 11 11
} testlength4;
int length4 = sizeof(testlength4); //2个字节对齐,占用字节11 11 11 11,length = 8
#pragma pack()
int main(void)
{
  printf("length1 = %d.\\n",length1);
  printf("length2 = %d.\\n",length2);
  printf("length3 = %d.\\n",length3);
  printf("length4 = %d.\\n",length4);
  return 0;
}

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

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

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

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

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 存储
    +关注

    关注

    12

    文章

    3859

    浏览量

    84667
  • C++
    C++
    +关注

    关注

    21

    文章

    2066

    浏览量

    72900
  • 编译器
    +关注

    关注

    1

    文章

    1577

    浏览量

    48621
  • 变量
    +关注

    关注

    0

    文章

    596

    浏览量

    28112
  • 字节对齐
    +关注

    关注

    0

    文章

    5

    浏览量

    1495
收藏 人收藏

    评论

    相关推荐

    c语言中的字节对齐

    缺省情况下,C编译器为每一个变量或是数据单元按其自然对界条件分配空间。
    的头像 发表于 12-30 11:03 2425次阅读
    c语言中的<b class='flag-5'>字节</b><b class='flag-5'>对齐</b>

    C/C++中的整型常识

    和 long, 部分编译器还扩展了一些更长的整型,比如 long long 和 __int64, C99中增加了long long和unsigned long long;  &
    发表于 10-07 11:12

    C语言-结构体对齐详解

    :32位编译器,一般编译器默认对齐方式是4字节对齐。#include<stdio.h>
    发表于 07-12 16:41

    请问对RX23T似乎不能对c++进行编译,是编译器版本问题吗?

    对于RX23T似乎不能对c++进行编译,请问是编译器版本问题吗?
    发表于 07-23 06:47

    C++笔记010:C++C的扩展——register关键字增强

    的地址在C语言里面是会出错的。同样的代码我们放到C++编译环境下,发现编译是通过的!在C++中依然支持register关键字,
    发表于 08-11 12:34

    解决单片机开发字节对齐问题的方法

    单片机开发重点-字节对齐问题在缺省情况下,C编译器为每一个变量或是数据单元按其自然对界条件分配空间。一般地,可以通过下面的方法来改变
    发表于 11-22 06:06

    GPIO_PIN_RESET与C++编译器不兼容是什么原因导致的

    您可以将返回值解释为布尔值(并将值作为布尔值传递给 gpio 读取和写入,只要您在 C编译您的项目,但一旦尝试在 C++编译,它们与布尔值不兼容但返回 GPIO_PIN_SET
    发表于 12-19 07:46

    S32DS C编译器/标准S32DS C++编译器-优化,,(-O3) 和 (-Os) 的MCU功能和性能是否完全相同?

    对于S32DS C编译器/标准S32DS C++编译器-优化,当我们将设置从最优化(-O3)更改为优化大小(-Os)时,使用相同的源代码,MCU功能和性能是否保持完全相同?如果不是,会
    发表于 04-06 07:48

    MCUXPRESSO编译器C++有问题怎么处理?

    我的 MCUXPRESSO 编译器 C++ 有问题
    发表于 04-20 06:11

    如何为Arm编译Cc++代码

    编写CC++应用程序时,需要使用编译器工具链将其编译为机器代码。然后,您可以在基于Arm的处理上运行此
    发表于 08-02 17:28

    Arm C/C++编译器开发人员和参考指南

    提供帮助您使用Arm®编译器Linux版的Arm®C/C++编译器组件的信息。Arm®C/C++
    发表于 08-10 06:17

    Arm C/C++编译器22.1版开发人员和参考指南

    提供帮助您使用ARM®编译器Linux版的ARM®C/C++编译器组件的信息。 ARM®C/C++
    发表于 08-11 07:46

    单片机开发重点-字节对齐问题

    单片机开发重点-字节对齐问题在缺省情况下,C编译器为每一个变量或是数据单元按其自然对界条件分配空间。一般地,可以通过下面的方法来改变缺省的对
    发表于 11-13 13:06 6次下载
    单片机开发重点-<b class='flag-5'>字节</b><b class='flag-5'>对齐</b>问题

    C编译器缺省字节对齐方式(自然对界)

    缺省情况下,C编译器为每一个变量或是数据单元按其自然对界条件分配空间。
    的头像 发表于 07-29 09:27 1724次阅读

    keil arm工程中结构体1字节对齐如何实现

    体的默认对齐方式和规则 结构体在Keil Arm工程中的默认对齐方式是根据编译器或者编译器选项来
    的头像 发表于 01-05 14:40 1172次阅读