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

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

3天内不再提示

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

电子工程师 来源:嵌入式与Linux那些事 作者:嵌入式与Linux那些 2022-07-29 09:27 次阅读

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


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

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

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

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

例子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结构体中,最大的成员为flaot x3,因些此结构体的自然对界条件为4字节对齐。则结构体长度就为12字节,内存布局为1100 1111 1000。

例子2:


							
#include <stdio.h>//#pragma pack(2)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 = 8int main(void) { printf("length1 = %d. ",length1); printf("length2 = %d. ",length2); printf("length3 = %d. ",length3); printf("length4 = %d. ",length4); return 0; }

改变缺省的对界条件(指定对界) · 使用伪指令#pragma pack (n),C编译器将按照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。

例子:


							
#include <stdio.h>#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 = 8int main(void) { printf("length1 = %d. ",length1); printf("length2 = %d. ",length2); printf("length3 = %d. ",length3); printf("length4 = %d. ",length4); return 0; }

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

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

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

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

审核编辑:汤梓红


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

    关注

    1

    文章

    38

    浏览量

    13875
  • 字节对齐
    +关注

    关注

    0

    文章

    5

    浏览量

    1495

原文标题:又错了,字节对齐及#pragma pack的使用

文章出处:【微信号:嵌入式与Linux那些事,微信公众号:嵌入式与Linux那些事】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    c语言中的字节对齐

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

    C语言-结构体对齐详解

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

    RM48HDK平台CCS结构体字节对齐总是咨询

    硬件平台:RM48HDK  软件平台:5.4.0.00091  编译器:TI V5.0.6 我在程序中想对一个结构体增加单字节对齐属性,增加方式如下: 1、参照《ARM Optimiz
    发表于 05-25 10:38

    希望所有字符串文字对齐到2字节是否有编译器设置?

    我在第三方库中有一个函数,其中MSG必须对齐到2个字节。默认情况下,字符串文本对齐到1个字节。我希望所有字符串文字对齐到2
    发表于 09-26 17:22

    请问lwip中是要求禁止编译器的字对齐吗?

    #define PACK_STRUCT_END#define PACK_STRUCT_FIELD(x) x这几个宏定义在这其实是啥也没做 ,但在LWIP中不是要求禁止编译器的字对齐吗?我知道在keil中是使用的 #define PACK_STRUCT_BEGIN __p
    发表于 11-06 22:36

    align为什么要8字节对齐

    ) CPU_STKFLOAT_TASK_STK[FLOAT_STK_SIZE];//任务函数void float_task(void *p_arg);问题2:本身编译器都会在编译时都会对齐的,那我们什么时候需要强制
    发表于 04-23 00:21

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

    单片机开发重点-字节对齐问题在缺省情况下,C编译器为每一个变量或是数据单元按其自然
    发表于 11-22 06:06

    C51编译器如何区分位地址和字节地址?

    C51编译器如何区分位地址和字节地址
    发表于 10-25 07:10

    C51编译器如何区分位地址和字节地址?

    C51编译器如何区分位地址和字节地址
    发表于 10-31 08:30

    C语言中Linux字节对齐的问题

    ,于是经过排查,是因为传递消息的结构体没有考虑字节对齐的问题。 随手整理一下C语言中字节对齐的问题与大家一起分享。 一、概念 对齐跟数据在内
    的头像 发表于 08-16 11:25 2180次阅读
    C语言中Linux<b class='flag-5'>字节</b><b class='flag-5'>对齐</b>的问题

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

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

    STM32 终极字节对齐解析

    一、全局变量对齐问题:基本上用户定义的变量是几个字节就是几字节对齐,这个比较好理解。uint8_t定义变量地址要1字节
    发表于 11-23 18:06 11次下载
    STM32 终极<b class='flag-5'>字节</b><b class='flag-5'>对齐</b>解析

    单片机字节对齐

    对齐原则:数据存放的地址需要是其类型长度的整数倍;字节对齐的作用不仅是便于cpu快速访问,同时合理的利用字节对齐可以有效地节省存储空间。许多
    发表于 12-01 15:21 11次下载
    单片机<b class='flag-5'>字节</b><b class='flag-5'>对齐</b>

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

    C/C++编译器缺省字节对齐方式自然对界。即在缺省
    的头像 发表于 04-15 11:24 714次阅读

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

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