• 嵌入式 字节对齐的设置


    最近写蓝牙协议,数据必须按协议中指定的报文进行传输,但由于默认处理器有字节对齐,而一旦多一个字节都会导致通信错误,所以这里记录一下字节对齐的处理。

    1 介绍

    CPU不会一个字节一个字节地读或写内存,而是一次访问2/4/6/8/16/32/64字节,因为这比读一个字节要快得多。假设CPU按四字节对齐,我们把四字节称为一个chunk,此时要读内存0x03-0x06的内容,CPU就会读取0x00~0x03和0x04-0x07两个chunk,然后把两个chunk读到的内容移位并组合返回给用户。

    假设CPU按照4字节进行对齐,现在来看一个结构体:

    struct S1{
    	char a;
    	char b;
    };
    
    • 1
    • 2
    • 3
    • 4

    CPU就会在结构体最后填充两个字节,以保证字节对齐。注意这个对齐不总是在最后的,而是数据类型所对应的变量需要字节对齐,比如

    struct S2{
    	uint8_t a;
    	uint16_t b;
    };
    
    • 1
    • 2
    • 3
    • 4

    由于uint16_t为2字节,需要2字节对齐,而前面的uint8_t只有1字节,故会在a后面填充1个字节,而对于结构体变量S2来说,其需要四字节对齐,故还会在b后面填充一个字节。

    • 变量类型占多少个字节就需要几字节对齐,比如uint8_t为1字节,则它放在内存中任何位置都可以

    2 设置字节对齐

    2.1 pack注释

    我们可以使用pack pragma来设置对于struct、union和class的字节对齐:

    1、保存当前系统字节对齐的状态,对指定的结构对齐完恢复原先对齐数
    #pragma pack(push, N)
    待字节对齐的struct、union和class
    #pragma pack(pop)
    注:
    #pragma pach(push,N)等价于
    #pragma pack(push)
    #pragma pack(N)
    2、作用同上
    #pragma pack(N)
    待字节对齐的struct、union和class
    #pragma pack()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    看一个例子:

    #pragma pack(push, 1)
    struct S3 {
        char m1;      // 1-byte
        double m2;    // 8-byte
    };
    #pragma pack(pop)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    这样就让这个结构体进行1字节对齐,即不进行对齐。此时结构体的大小就是9字节。

    2.2 __attribute__关键字

    • __attribute__ ((packed)):取消在编译过程中的优化对齐,按照实际占用字节数进行对齐
    • __attribute((aligned (n))):让所作用的结构体成员对齐在n字节边界上。如果结构体中有成员变量的字节长度大于n,则按照最大成员变量的字节长度来对齐。
    struct  person1{
    	char *name;
    	int  age;
    	char score;
    	int  id;
    }__attribute__ ((packed));
    
    struct  person2{
    	char *name;
    	int  age;
    	char score;
    	int  id;
    }__attribute((aligned (n)));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
  • 相关阅读:
    SpringCLoud——Nacos配置中心
    ESP32idf组件中缺少头文件error: mqtt_client.h: No such file or directory
    【波形/信号发生器】基于 STC1524K32S4 for C on Keil
    【SpringMVC】JSR 303与拦截器注解使用
    MongoDB聚合运算符:$sin
    跨网段通信实战(支持静态路由表的家用路由)
    U盘RAW格式无法格式化怎么办?
    java毕业设计财务信息管理mybatis+源码+调试部署+系统+数据库+lw
    计算摄影——妆造迁移
    微信小程序:实现列表单选
  • 原文地址:https://blog.csdn.net/tilblackout/article/details/127918171