结构体对齐与压缩对齐操作

先看一组测试代码:

c 复制代码
#include "stdio.h"

typedef struct {
    unsigned char   a;
    float           b;
    unsigned short  c;
    int             d;
}para_t;

typedef struct {
    unsigned char   a;
    float           b;
    unsigned short  c;
    int             d;
}__attribute__((packed)) para_packed_t;

int main(void){
    printf("c test start,build at %s,%s\r\n",__DATE__,__TIME__);

    printf("\"unsigned char \" size is %d\r\n",sizeof(unsigned char));
    printf("\"float         \" size is %d\r\n",sizeof(float));
    printf("\"unsigned short\" size is %d\r\n",sizeof(unsigned short));
    printf("\"int           \" size is %d\r\n",sizeof(int));

    para_t para;

    printf("para size is  %d\r\n",sizeof(para_t));

    printf("para member \"a\" index is %d,address is 0x%x\r\n",offsetof(para_t,a),&para.a);
    printf("para member \"b\" index is %d,address is 0x%x\r\n",offsetof(para_t,b),&para.b);
    printf("para member \"c\" index is %d,address is 0x%x\r\n",offsetof(para_t,c),&para.c);
    printf("para member \"d\" index is %d,address is 0x%x\r\n",offsetof(para_t,d),&para.d);

    para_packed_t para_packed;

    printf("para_packed size is  %d\r\n",sizeof(para_packed_t));

    printf("para_packed member \"a\" index is %d,address is 0x%x\r\n",offsetof(para_packed_t,a),&para_packed.a);
    printf("para_packed member \"b\" index is %d,address is 0x%x\r\n",offsetof(para_packed_t,b),&para_packed.b);
    printf("para_packed member \"c\" index is %d,address is 0x%x\r\n",offsetof(para_packed_t,c),&para_packed.c);
    printf("para_packed member \"d\" index is %d,address is 0x%x\r\n",offsetof(para_packed_t,d),&para_packed.d);

    printf("c test end!\r\n");

    return 0;
}

执行后,结果如下:

bash 复制代码
"unsigned char " size is 1
"float         " size is 4
"unsigned short" size is 2
"int           " size is 4
para size is  16
para member "a" index is 0,address is 0x61fe40
para member "b" index is 4,address is 0x61fe44
para member "c" index is 8,address is 0x61fe48
para member "d" index is 12,address is 0x61fe4c
para_packed size is  11
para_packed member "a" index is 0,address is 0x61fe35
para_packed member "b" index is 1,address is 0x61fe36
para_packed member "c" index is 5,address is 0x61fe3a
para_packed member "d" index is 7,address is 0x61fe3c

可以看出对于 typedef struct { ...} para_t,编译器自动对齐,在成员a之后填充了3个字节,在成员c之后填充了2个字节,最终得到整个结构体是16字节,且每个成员的地址都是4的倍数;

对于typedef struct {...}__attribute__((packed)) para_packed_t,加了取消对齐的操作,也可以叫做1字节对齐,成员之间没有填充,最终得到整个结构体是11字节,成员的地址不全是4的倍数。

加了packed的作用:

结构体占用空间最小,不浪费空间,对嵌入式数据存储、通信协议封装、硬件寄存器等非常适用,但是也会带来一个问题,非对齐访问,会导致CPU访问速度变慢,对不支持非对齐访问的硬件会导致hardfault异常。

对于不同平台,取消编译器对齐的写法不一样:

GCC:__attribute__((packed))

MDK:__packed

扩展:

除了编译器根据最大成员默认对齐以外,我们还可以使用__attribute__((aligned(n)))指定对齐数,这里n可以取为4,8,16等。

Cortex-m0、C2000不支持非对齐访问,Cortex-m3、m4支持非对齐访问。

复制代码
                        ------------------END------------------