精华内容
下载资源
问答
  • 正文大家好,我是bug菌!最近看到一些朋友在交流结构体对齐方面的一些问题,从他们的交谈中隐隐约感觉有几个朋友对结构体成员的对齐理解上有点偏差,不能说完全不对吧,毕竟这是老生常谈的问题了~所...


    正文


    大家好,我是bug菌!

    最近看到一些朋友在交流结构体对齐方面的一些问题,从他们的交谈中隐隐约感觉有几个朋友对结构体成员的对齐理解上有点偏差,不能说完全不对吧,毕竟这是老生常谈的问题了~

    所以bug菌今天跟大家好好谈谈对齐这个话题~

    1

    变量与内存

    首先我们要明确,在嵌入式C语言中变量是什么?其实所谓的变量就是一小段内存。

    当你随心所欲的在C程序中定义着各种变量,有没有想过他们是如何被安排到相应内存上的?

    好吧,其实他们是怎么安排的,并不需要程序员太多的操心,这个映射过程都是编译器自动给大家分配的,(可以借助动态内存的角度去看待这个分配问题),因为大部分变量在一定内存区域上是可以任意选择地址的,比如你定义一个全局的int gVar 变量,在不进行特殊指定内存位置的情况下,其编译后所分配的内存地址并不一定每次都是相同的;当然,每次编译完成便会确定下来,并且程序中对该变量的访问,均会使用所确定下来的内存地址。

    既然变量的地址分配过程由编译器自动完成,但有时候我们想把一些或者某个变量放在固定的内存地址处等,此时就需要通过一些语法来告诉编译器该如何分配这些指定变量内存的分配,比如要做复位数据恢复等。

    然而内存的对齐问题也是对这些变量分配位置处理的一种方式,通常我们看到的align或者pack等就是来干预编译器的这块处理的。

    2

    结构体对齐

    理解了上面的一个思路,那么我们来分析分析结构体对齐问题。

    参考demo:

     1#include <stdio.h>
     2#include <stdlib.h>
     3
     4/*默认对齐方式*/ 
     5typedef struct _tag_ContrlObj1
     6{
     7    char member1;
     8    int member2;
     9
    10}sContrl1;
    11
    12/*1字节对齐*/ 
    13#pragma pack(1) 
    14typedef struct _tag_ContrlObj2
    15{
    16    char member1;
    17    int member2;
    18
    19}sContrl2;
    20#pragma pack()
    21
    22/*2字节对齐*/ 
    23#pragma pack(2)
    24typedef struct _tag_ContrlObj3
    25{
    26    char member1;
    27    int member2;
    28
    29}sContrl3;
    30#pragma pack()
    31
    32/*4字节对齐*/ 
    33#pragma pack(4)
    34typedef struct _tag_ContrlObj4
    35{
    36    char member1;
    37    int member2;
    38
    39}sContrl4;
    40#pragma pack()
    41
    42/*8字节对齐*/  
    43#pragma pack(8)
    44typedef struct _tag_ContrlObj5
    45{
    46    char member1;
    47    int member2;
    48
    49}sContrl5;
    50#pragma pack()
    51
    52int main(int argc, char *argv[]) {
    53
    54    printf("default:%d\n",sizeof(sContrl1));
    55    printf("pack(1):%d\n",sizeof(sContrl2)); 
    56    printf("pack(2):%d\n",sizeof(sContrl3));
    57    printf("pack(4):%d\n",sizeof(sContrl4));
    58    printf("pack(5):%d\n",sizeof(sContrl5));
    59
    60    return 0;
    61}
    

    运行结果:

    以上编译结果采用的是32位编译器,默认对齐方式是4个字节,char类型占据1个字节,int占据4个字节,下面简单分析一下结果:

    1、默认方式,采用4个字节对齐,那么char后面需要填充3个字节,然后存放int类型,所以结构体大小输出为8。

    2、1字节对齐方式,直接紧凑排列,很多人也叫不进行对齐处理,所以输出结果是5。

    3、2字节对齐方式,其实和4个字节对齐是类似的,char按照2字节对齐,所以后面需要填充一个字节,这样int才能以两字节对齐排布,此时整个结构体占据6个字节。

    4、4字节对齐方式与默认对齐方式一致,最后看看8字节对齐,此时char类型与int类型完全能够被8个字节容纳,而该结构体最大数据类型是4个字节,所以char后面会预留3个字节,进行4字节对齐,然后放置int类型,此时与4字节对齐是一致的。

    那么一些朋友会问,是不是在上面的8字节例子中再加入一个char类型的成员,整个结构体就会占据16个字节了呢?

    1/*8字节对齐*/  
    2#pragma pack(8)
    3typedef struct _tag_ContrlObj5
    4{
    5    char  member1;
    6    int   member2;
    7    char  member3;
    8}sContrl5;
    9#pragma pack()
    
    

    其输出结果如下:

    结构体所占据的字节是12个,那是不是认为8字节对齐没有意义呢?

    我们再看一个实验:

    1/*8字节对齐*/  
    2#pragma pack(8)
    3typedef struct _tag_ContrlObj5
    4{
    5    char     member1;
    6    double   member2;
    7    char     member3;
    8}sContrl5;
    9#pragma pack()
    
    

    此时double占据了8个字节,按照前面的思路应该是4+8+4,应该最终结构体的大小是16个字节,而结果显示:

    输出结果显示24=8+8+8的形式,大家也可以直接采用打印结构体成员地址的办法查看是几个字节对齐,有点晕,到底编译器这一块是怎么处理的呢?

    结论是:对齐字节数 = min<当前指定的pack值,最大成员所占字节大小>。

    很多朋友其实研究到这个阶段基本上就没有再继续探究了~嵌入式C语言一定要跟硬件结合理解~

    3

    内存对齐

    其实所谓的结构体对齐,并不是简单的1个字节、两个字节等多个字节的排列组合,而是在对应对齐地址上分布。

    首先对齐需要解决的问题是什么 ? 即为啥需要对齐?

    提高内存的访问效率,也可以说是受CPU等硬件方面的限制,按照特定的对齐地址进行数据的访问要快于跨非对齐地址的内存访问;并且有些平台仅支持对齐方式访问,非对齐方式会直接运行错误。

    为了加快相关数据的正确访问,编译器会把相关的变量尽量的放到对齐的地址上,也就是默认的对齐方式,比如CPU在偶数地址上访问比较快,那么就会采用2个字节对齐的方式。

    所以结构体内部成员并不是简单成员字节个数的对齐拼凑,而是让结构体成员落在对齐的地址上以便访问。如下图所示,当进行2字节对齐,如果只是简单的拼凑,两种分布都是可以的,但是左侧才是正确的2字节对齐方式,char成员变量的地址是2,int变量的地址是4,均为2字节的倍数。

    总结一下: 结构体对齐不再是简单的字节个数的拼凑,而是要与内存地址进行挂钩~一般我们也可以理解为内存地址分配是多少字节的倍数,就是多少直接对齐~

    enjoy~

    最后

        今天的内容就到这里了,觉得有所收获,记得点个哦~~

    推荐专辑  点击蓝色字体即可跳转

    ☞  MCU进阶专辑 

    ☞  嵌入式C语言进阶专辑 

    ☞  “bug说”专辑 

    ☞ 专辑|Linux应用程序编程大全

    ☞ 专辑|学点网络知识

    ☞ 专辑|手撕C语言

    ☞ 专辑|手撕C++语言

    ☞ 专辑|经验分享

    ☞ 专辑|电能控制技术

    展开全文
  • 结构体对齐原则

    2021-02-19 11:34:55
    原则一:每个成员所放位置:结构体中元素是按照定义顺序一个一个放到内存中去的,但并不是紧密排列的。从结构体存储的首地址开始,每一个元素放置到内存中时,它都会认为内存是以它自己的大小来划分的,因此元素放置...

    原则一:每个成员所放位置:结构体中元素是按照定义顺序一个一个放到内存中去的,但并不是紧密排列的。从结构体存储的首地址开始,每一个元素放置到内存中时,它都会认为内存是以它自己的大小来划分的,因此元素放置的位置一定会在自己宽度的整数倍上开始(以结构体变量首地址为0计算)。

    原则二:最后结算:在经过第一原则分析后,检查计算出的存储单元是否为所有元素中最宽的元素的长度的整数倍,是,则结束;若不是,则补齐为它的整数倍。

    转载地址:https://blog.csdn.net/u011404495/article/details/54837797

    leetcode中描述更准确:

    基本类型才需要自己宽度的整数倍上开始;

    内存对齐:编译器将程序中的每个“数据单元”安排在字的整数倍的地址指向的内存之中
    内存对齐的原则:

    结构体变量的首地址能够被其最宽基本类型成员大小与对齐基数中的较小者所整除;
    结构体每个成员相对于结构体首地址的偏移量 (offset) 都是该成员大小与对齐基数中的较小者的整数倍,如有需要编译器会在成员之间加上填充字节 (internal padding);
    结构体的总大小为结构体最宽基本类型成员大小与对齐基数中的较小者的整数倍,如有需要编译器会在最末一个成员之后加上填充字节 (trailing padding)。

    C++ sizeof(string) 基于VS2015编译器 转载地址:https://blog.csdn.net/sols000/article/details/103989637?utm_medium=distribute.pc_relevant_bbs_down.none-task-blog-baidujs-1.nonecase&depth_1-utm_source=distribute.pc_relevant_bbs_down.none-task-blog-baidujs-1.nonecase

    名称X86 (字节数)X64(字节数)
    Allocator48
    原始字符传 Data 位置15+1  最多包含15个字符加一个结束符‘\0’15+1  最多包含15个字符加一个结束符‘\0’
    字符长度 Size48
    当前容量 Capacity48
    总计2840

     

    展开全文
  • 基本的结构体对齐知识点击这里 ①结构体嵌套对齐以及结构体中含有数组的对齐 32位系统环境 规则一:结构体中含有数组,数组元素类型和结构中其余的最大类型取较大者 对齐 规则二:结构体S2中嵌套结构体S1,则按照S1...


    基本的结构体对齐知识点击这里

    ①结构体嵌套对齐以及结构体中含有数组的对齐

    32位系统环境
    规则一:结构体中含有数组,数组元素类型和结构中其余的最大类型取较大者 对齐
    规则二:结构体S2中嵌套结构体S1,则按照S1的最大元素类型和S2中各元素类型取较大者对齐
    就是max(sizeof(struct S1),sizeof(max_type_of_S2))

    注释的数字表示偏移量(就是地址)

    #include<iostream>
    #include<vector>
    struct S1 {
    	char a;// 0
    	double b;// 8-15
    	short c[2];//16-19,因为double的8比short的2大,引用规则一
    	//共24
    };
    struct S2 {
    	struct S1 a;// , 0-23
    	int b;//24-27
    	char c;//28
    	// 最后按S1的最大类型double的8字节对齐,因为double比S2的int和char字节数都大,最后
    	//整个S2按照8字节对齐
    };
    int main() {
    	using namespace std;
    	cout << sizeof(S1) << " " << sizeof(S2) << endl;
    }
    

    下面代码把S1中的

    #include<iostream>
    #include<vector>
    struct S1 {
    	char a;// 0
    	int b;// 4-7
    	short c;//8-9
    	//共12
    };
    struct S2 {
    	struct S1 a;//  0-11,按4字节对齐
    	int b;//12-15,S2中S1类型按4字节对齐,int和char中比较大的是int,两个都一样是4字节,所以整个结构按4字节对齐
    	char c;//16
    	//原来占17字节,但是得按照4字节对齐,所以是20
    
    };
    int main() {
    	using namespace std;
    	cout << sizeof(S1) << " " << sizeof(S2) << endl;
    }
    

    ②其余的对齐规则

    规则三:static成员放在了静态存储区,不影响sizeof结果!!

    展开全文
  • 结构体对齐方式总结

    2021-03-31 23:07:02
    结构体对齐方式有以下两种设置方法: 1、#pragma pack(n) //n为对齐格式的字节数 #pragma pack() //取消对齐格式操作 举例说明 使用#pragma pack(1)以一字节对齐 #include <stdio.h> #pragma pack(1) ...

    结构体对齐方式有以下两种设置方法:

    1、#pragma pack(n) //n为对齐格式的字节数

         #pragma pack()   //取消对齐格式操作

    举例说明

    使用#pragma pack(1)以一字节对齐

    #include <stdio.h>
    
    #pragma pack(1)
    typedef struct user_info
    {
        int age;
        char sex;
        char name[14];
    } user_infos;
    
    int main()
    {
        user_infos user;
        printf("%d\n", sizeof(user));
        return 0;
    }
    #pragma pack()

    运行后输出为19,char一个字节,int 4个字节,char数组14个字节

    如果不使用#pragma pack()控制结构体对齐方式,占多少字节呢

    #include <stdio.h>
    
    typedef struct user_info
    {
        int age;
        char sex;
        char name[14];
    } user_infos;
    
    int main()
    {
        user_infos user;
        printf("%d\n", sizeof(user));
        return 0;
    }

    输出是20

    2、__attribute__选项

         __attribute__((aligned(x)))  让结构体的成员在n字节对齐,但是如果结构体有成员的长度大于x,则按照最大成员的长度来对齐

         __attribute__((packed)) 设置后的结构体变量及成员将使用最小的对齐方式,变量以一字节对齐,域是以位对齐

    举例说明

    使用__attribute__((aligned(1)))以1字节对齐 

    #include <stdio.h>
    
    struct user_info
    {
        char sex;
        int age;
        char name[14];
    }__attribute__((aligned(1)));
    
    int main()
    {
        printf("%d\n", sizeof(struct user_info));
        return 0;
    }
    

    输出为24,虽然是希望设置以1字节对齐,然而成员中有int变量以及字符数组变量,则按照4字节对齐

    以__attribute__((packed))使用最小对齐方式

    #include <stdio.h>
    
    struct user_info
    {
        char sex;
        int age;
        char name[14];
    } __attribute__((packed));
    
    int main()
    {
        printf("%d\n", sizeof(struct user_info));
        return 0;
    }
    

    输出为19

    展开全文
  • 结构体对齐

    2021-09-06 10:24:25
    1、不但结构体的成员有有效对齐值,结构体本身也有对齐值,这主要是考虑结构体的数组,对于结构体或者类,要将其补齐为其有效对齐值的整数倍。结构体的有效对齐值是其最大数据成员的自身对齐值; 2、存放成员的起始...
  • 结构体对齐详解

    2017-09-04 16:43:39
    阅读说明1、在文中要注意#pragma pack()函数的使用2、本文中博主用于演示的是linux32位系统3、如果有...看完之后醍醐灌顶5、标注为“注”的是我的注释我认为结构体对齐要考虑三点:1、确认结构体对齐值(模数),通
  • 什么是字节对齐 这跟读取数据有关,cpu读取一次能读取到的内存大小跟数据总线的位数有关,如果数据总线为16位,那么cpu一次能够读取2字节;如果为32位那么cpu一次可以读取4字节,而读取数据是需要消耗时间的,为了...
  • 最近在找一个离奇的问题,最终虽然找到是强制转换导致问题,但实际上还是结构体对齐问题跟协议设计问题 背景: 某端口收到一帧数据,原始数据放在uint8_t *pBuf 里面 一般来说,为了解析方便点,要根据协议设计一个...
  • 结构体对齐的重要性

    千次阅读 2019-07-04 16:12:39
      最近在工作中被结构体对齐问题坑了一天的时间,郁闷的不行不行,特别记录下来,以供大家参考。    事情是这样的,因业务需要增加了一个结构体,里面用到了信号量,当时写完联调的时候只测试了windows平台,...
  •  对齐跟数据在内存中的位置有关。如果一个变量的内存地址正好位于它长度的整数倍,他就被称做自然对齐。比如在32位cpu下,假设一个整型变量的地址为0x00000004,那它就是自然对齐的。   二、为什么要字节对齐  ...
  • 结构体对齐规则

    2019-07-28 18:42:26
    结构体对齐
  • 一、结构体对齐 首先通过一个例子说明结构体对齐,可以看到,下面这个结构体占32字节(32位) typedef struct { double d; short s; int i; char c; short ss; char cc; int ii; } A; 这个是8字节默认对齐...
  • Keil中取消结构体对齐的方法

    千次阅读 2019-02-10 14:13:04
    Keil中取消结构体对齐的方法 我在写通讯协议的时候喜欢使用 Union 的形式将整个数据包按需处理,接收数据时使用数组形式来接收,解析数据则使用结构体形式来解析,伪代码如下。 union { uint8_t tab[16]; struct {...
  • 结构体对齐的步骤:             1、结构体各成员对齐             2、整个结构体圆整...
  • 结构体对齐计算方式

    2021-03-19 15:24:41
    结构体对齐计算方式 结构体的大小也不是成员类型大小的简单相加。需要考虑到系统在存储结构体变量时的地址对齐问题。 由于存储变量地址对齐的问题,结构体大小计算必须满足两条原则: 一、结构体成员的偏移量必须是...
  • 看了很多关于结构体对齐,有些很全面,但总是记不住,后来看计算机组成原理后猛然想明白了,计算机从内存中往寄存器读取数据的时候是一次读入4、8个字节,如果你的结构体中有数据最好一次读取后这4、8个字节中有完整...
  • 简单易懂的C结构体对齐原则 结构体的对齐原则非常简单,只需要理解两个点就能透彻理解结构体对齐。分别是: 结构体内成员的对齐长度,该长度就是该成员的类型长度; 结构体的对齐长度,该长度默认情况下是成员类型...
  • #pragma pack(n)说明程序中的结构体是按n字节对齐的 实例 假如有以下结构体 typedef struct _A { char a; int b; short c; long long d; }A; typedef struct _B { int a; long long b; c...
  • 结构体对齐、char*str/char str[] 问题 1.结构体对齐的问题(32位下) 1.1结构体字节对齐问题 看下面代码: #include <stdio.h> #include <string.h> struct { short a1; short a2; short a3; }A;...
  • C语言之结构体对齐

    2021-07-17 10:03:41
    本次让我们来一起学习一下C语言中我们该如何将结构体内存对齐呢? 什么是结构体? struct A{ //struct是关键字, A是结构体标志 int a; //a,b是结构体成员列表 ...结构体对齐规则: 1.计算结构体大小不是元素单纯
  • typedef struct AEE_LpFilter{ long long dummy; // 添加"long long" dummy field,保证8 byte alignment float midBuf[OVLPLEN]; // 滤波器中间BUF float coef[12]; // 滤波器系数 float hist[4];...
  • 一、内存对齐 1、对齐原因: ①平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。 ②性能原因:数据结构(尤其是栈...
  • 【IoT】STM32 结构体对齐规则

    千次阅读 2019-04-01 09:18:40
    在相同的对齐方式下,结构体内部数据定义的顺序不同,结构体整体占据内存空间也不同。 如下结构体定义: struct A { // a 的自身对齐值为 4,偏移地址为 0x00~0x03,a 的起始地址 0x00 满足 0x00%4=0 int a; // ...
  • 结构体对齐(图解)与位域

    千次阅读 2017-09-04 14:36:11
    一、结构体对齐 在计算结构体大时往往需要考虑到结构体对齐,简单的总结下我的一些经验。  结构体对齐时,先找出本结构中最大类型的长度,先考虑自身对齐,然后在与最大类型对齐,最后考虑整个结构对齐(与最大...
  • 结构体对齐和补齐(详细解释)

    千次阅读 多人点赞 2019-08-16 17:28:25
    结构体对齐和补齐的规则: 对齐:假定从零地址开始,每成员的起始地址编号,必须是它本身字节数的整数倍。 补齐:结构的总字节数必须是它最大成员的整数倍。 注意:在Linux系统下计算补齐、对齐时,成员超过4...
  • gcc结构体对齐

    2017-04-09 10:20:06
    struct A a= //gcc支持的一种...{ //结构体变量对齐存放,所以a的大小为8字节  .a=4,  .b=555, } // 定义类型的同时定义变量,s1是一个变量。 struct student {  char name[20];  int age; }s

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 53,570
精华内容 21,428
关键字:

结构体对齐