嵌入式C代码属性怎么定义?( 二 )

可以看到,c2 的地址是按照4字节对齐
a = 0x404030b = 0x404034c1 = 0x404038c2 = 0x40403c通过 aligned 属性声明,虽然可以显示的指定变量地址的对齐方式,但是也会因为边界对齐造成一定的内存空间浪费 。
地址对齐的好处是,为了配合计算机硬件设计,可以简化CPU和内存RAM之间的接口和硬件设计 。
例如,一个32位的计算机操作系统,在CPU读取内存时,硬件设计上可能只支持4字节或者4字节倍数对齐地址访问,CPU 每次向 RAM 读写数据时,一个周期可以读写4字节 。如果我们把一个int型数据就放在4字节对齐的地址上,那么CPU就可以一次性把数据读取完毕,否则可能需要读取两次 。
3.2 结构体对齐结构体作为一种复杂的数据类型,编译器在给一个结构体变量分配存储空间时,不仅要考虑结构体内各个成员的对齐,还要考虑结构体整体的对齐 。
为了结构体各成员对齐,编译器可能会在结构体内填充一些字节 。为了结构体的整体对齐,编译器可能会在结构体的末尾一些空间 。
#include <stdio.h>struct data {char a;int b;short c;};int main(){struct data s;printf("size = %dn", sizeof(s));printf("a = %pn", &s.a);printf("b = %pn", &s.b);printf("c = %pn", &s.c);return 0;}四字节对齐:占12字节
size = 12a = 0xffb6c374b = 0xffb6c378c = 0xffb6c37c结构体成员顺序不同,所占大小有可能不同:
#include <stdio.h>struct data {char a;short b;int c;};int main(){struct data s;printf("size = %dn", sizeof(s));printf("a = %pn", &s.a);printf("b = %pn", &s.b);printf("c = %pn", &s.c);return 0;}四字节对齐:占8字节
size = 8a = 0xffa2d9f8b = 0xffa2d9fac = 0xffa2d9fc显示的指定成员的对齐方式:
#include <stdio.h>struct data {char a;short b __attribute__((aligned(4)));int c;};int main(){struct data s;printf("size = %dn", sizeof(s));printf("a = %pn", &s.a);printf("b = %pn", &s.b);printf("c = %pn", &s.c);return 0;}四字节对齐:占12字节
size = 12a = 0xffb6c374b = 0xffb6c378c = 0xffb6c37c显示指定结构体对齐方式:
#include <stdio.h>struct data {char a;short b;int c;} __attribute__((aligned(16)));int main(){struct data s;printf("size = %dn", sizeof(s));printf("a = %pn", &s.a);printf("b = %pn", &s.b);printf("c = %pn", &s.c);return 0;}16字节对齐,末尾填充8字节:占16字节
size = 16a = 0xffa2d9f8b = 0xffa2d9fac = 0xffa2d9fc3.3 编译器一定会按照 aligend 指定的方式对齐吗?我们通过这个属性声明,其实只是建议编译器按照这种大小地址对齐,但不能超过编译器允许的最大值 。一个编译器,对每个基本的数据类型都有默认的最大边界对齐字节数,如果超过了,则编译器只能按照它规定的最大对齐字节数来对变量分配地址 。
4. 属性声明:packedaligned 属性一般用来增大变量的地址对齐,元素之间地址对齐会造成一定的内存空洞,而packed属性则正好相反,一般用来减少地址对齐,指定变量或类型使用最可能小的地址对齐方式 。
显示的对结构体成员使用packed
#include <stdio.h>struct data {char a;short b __attribute__((packed));int c __attribute__((packed));};int main(){struct data s;printf("size = %dn", sizeof(s));printf("a = %pn", &s.a);printf("b = %pn", &s.b);printf("c = %pn", &s.c);return 0;}使用最小一字节对齐:
size = 7a = 0xfff38fb9b = 0xfff38fbac = 0xfff38fbc对整个结构体添加packed属性
struct data {char a;short b;int c;}__attribute__((packed));内核中的packed、aligned 声明
在内核源码中,我们经常看到aligned 和 packed 一起使用,即对一个变量或者类型同时使用packed 和 aligned 属性声明 。这样做的好处是即避免了结构体各成员间地址对齐产生的内存空洞,又指定了整个结构体的对齐方式 。
struct data {char a;short b;int c;} __attribute__((packed, aligned(8)));5. 属性声明:formatGNU 通过 __attribute__ 扩展的 format 属性,来指定变参函数的参数格式检查 。
它的使用方法如下:
__attribute__((format (archetype, string-index, frist-to-check)))void LOG(const char *fmt, ...) __attribute__((format(printf,1,2)));属性format(printf,1,2) 有3各参数,第一个参数pritnf 是告诉编译器,按照printf的标准来检查;第二个参数表示LOG()函数所有的参数列表中格式字符串的位置索引,第三个参数是告诉编译器要检查的参数的起始位置 。


推荐阅读