详解C语⾔结构体尾部:案例分析__attribute__((packed))
1、attribute
__attribute__书写特征是:__attribute__前后都有两个下划线,并且后⾯会紧跟⼀对括弧,括弧⾥⾯是相应的__attribute__参数。
__attribute__语法格式为:
__attribute__ ((attribute-list))
attribute__关键字主要是⽤来在函数或数据声明中设置其属性。此外 ,给函数赋给属性的主要⽬的在于让编译器进⾏优化,在函数声明中的__attribute((noreturn)),就是告诉编译器这个函数不会返回(noreturn)给调⽤者,以便编译器在优化时去掉不必要的函数返回代码。
2、GUN CC
闭经吃什么药GNU CC的⼀⼤特⾊就是__attribute__机制。__attribute__可以设置函数属性(Function Attribute)、变量属性(Variable Attribute)和类型属性(Type Attribute)。
函数属性(Function Attribute):函数属性可以帮助开发者把⼀些特性添加到函数声明中,从⽽可以使编译器在错误检查⽅⾯的功能更强⼤。
3、packed
packed属性:使⽤该属性可以使得变量或者结构体成员使⽤最⼩的对齐⽅式,即对变量是⼀字节对齐,对域(field)是位对齐。
如果你看过GPSR协议在TinyOS中的实现,你⼀定会注意到下⾯的语句:
typedef struct{
double x;
double y;
}__attribute__((packed)) position_t;
packed是类型属性(Type Attribute)的⼀个参数,使⽤packed可以减⼩对象占⽤的空间。需要注意的是,attribute属性的效⼒与你的连接器也有关,如果你的连接器最⼤只⽀持16字节对齐,那么你此时定义32字节对齐也是⽆济于事的。
使⽤该属性对struct或者union类型进⾏定义,设定其类型的每⼀个变量的内存约束。当⽤在enum类型定义时,暗⽰了应该使⽤最⼩完整的类型(it indicates that the smallest integral type should be ud)。
下⾯的例⼦中,my-packed-struct类型的变量数组中的值会紧凑在⼀起,但内部的成员变量s不会被“pack”,如果希望内部的成员变量也被packed的话,my-unpacked-struct也需要使⽤packed进⾏相应的约束。
struct my_unpacked_struct
{
char c;
int i;
};
struct my_packed_struct
{
char c;
int i;
struct my_unpacked_struct s;
}__attribute__ ((__packed__));
4、内存对齐
内存对齐,往往是由编译器来做的,如果你使⽤的是gcc,可以在定义变量时,添加__attribute__,来决定是否使⽤内存对齐,或是内存对齐到⼏个字节,以上⾯的结构体为例:2019年除夕
1. 4字节同样可指定对齐到8字节。
管理系
{
char name[7];
uint32_t id;
char subject[5];
} __attribute__ ((aligned(4)));
2. 不对齐,结构体的长度,就是各个变量长度的和
struct student
{
char name[7];
uint32_t id;
char subject[5];
} __attribute__ ((packed));
5、为什么要⽤ “ attribute ((packed)) ” 定义结构体
通常定义⼀个U32 ,CPU 期望 这个 U32 地址是 DW 对齐的, 这样对CPU访问 mem bus ⽐较友好。
重力所以,当我们定义这样⼀个结构体:
struct test{
char i,
uint32 a
}
那么,编译器会默认在 i 和 a 之间插⼊ rerve,确保 a 的位置是 4 对齐的。sizeof(test) = 8.
它就等效于:油菜花开
struct test{
char i,
char rerve[3],
uint32 a
}
加⼊ “attribute ((packed))” 的效果,则在于避免编译器 “⾃作聪明”。 告诉编译器,我们这⾥不需要补全。
struct __attribute__ ((__packed__)) test{
char i,
uint32 a
}
sizeof(test) = 5; 这会造成 a 地址不对齐,反⽽引⼊⿇烦。
6、⼀个例⼦
attribute ((packed)) 对齐或者取消对齐实例,要注意摆放的位置,不然没办法跟编译器经常兼容性的执⾏项⽬。下⾯看看⼀个例⼦就了解了:
#include<stdlib.h>
typedef struct{
char a;
short b;
int c;
}__attribute__ ((packed)) sttest ;
/*__attribute__ ((packed));*/
int main(void)
{
char stsize;
sttest stTest;
void*addra,*addrb,*addrc;
stsize =sizeof(sttest);
addra =&stTest.a;
addrb =&stTest.b;
addrc =&stTest.c;
新居入伙对联
printf("stsize is %d\n",stsize);
printf("a is %d\n",addra);
printf("a is %d\n",addrb);
printf("a is %d\n",addrc);
return0;2000年悉尼奥运会
}
执⾏结果:
再来看⼀个例⼦:packed的作⽤是取消字节对齐
typedef struct{
int i;//4
char a;//1
char b;//1
char c;//1
//1
}Test1;
typedef struct{
int i;//4
char a;//1
char b;//1
char c;//1
}__attribute__((packed))Test2;
typedef struct{
int i;//4
char a;//1
char b;//1
char c;//1
}__attribute__((__packed__))Test3;
int
main(int argc,char*argv[])
安全依恋{
printf("Test1 = %d \r\n",sizeof(Test1)); printf("Test2 = %d \r\n",sizeof(Test2)); printf("Test3 = %d \r\n",sizeof(Test3));
return0;
}
/**输出结果:
Test1 = 8
Test2 = 7
Test3 = 7
*/