gcc之__attribute__简介及对齐参数介绍
GNU C的一大特色就是__attribute__机制。__attribute__机制可以设置函数属性(Function Attribute)、变量属性(Variable Attribute)和类型属性(Type Attribute)。
__attribute__语法格式为:__attribute__((attribute-list))。
__attribute__对结构体(struct)或共用体(union)进行属性设置:
大致有六个参数值可以被设定,即:aligned,packed,transparent_union,deprecated和may_alias。
在使用__attribute__参数时,你也可以在参数的前后都加上“__”(两个下划线),例如,使用__aligned__而不是aligned,这样,你就可以在相应的头文件里使用它而不需要关心头文件里是否有重名的宏定义。
如上所述,你可以手动指定对齐的格式,同样,你也可以使用默认的对齐方式。如果aligned后面不指定数值,那么编译器将依据你的目标机器情况使用最大最有益的对齐方式。
为什么需要内存对齐?
-
- CPU对内存的读取不是连续的,而是分块读取的,块的大小只能是1、2、4、8、16字节
- 当读取操作的数据未对齐,则需要两次总线周期来访问内存,因此性能会大打折扣
- 某些硬件平台只能从规定的地址处取某些特定类型的数据,否则则抛出硬件异常
下面以目标机32位为例(4字节)
(1). __attribute__ ((packed)) 等价于 __attribute__((packed,aligned(1))) 以一个字节对齐
struct __attribute__ ((packed)) s1 {
char a; // 1 个字节
int i ; // 4个字节
};
(2). __attribute__((packed,aligned(n))) 以n个字节对齐,n=1/2/4/8/16
struct __attribute__((packed,aligned(4))) s2 {
char a; // 1 个字节
int i ; // 4个字节
};
(3).
#pragma pack(n) //以n个字节对齐,n=1/2/4/8/16
struct s4 {
char a; // 1 个字节
int i; // 4 个字节
char b; // 1 个字节
};
#pragma pack()
下面这个例子以32位目标机为例:
#include <stdio.h>
#include <stdlib.h>
struct s0 {
char a; //1个字节
int i; //4个字节
};
struct __attribute__ ((packed)) s1 {
char a; //1个字节
int i ; //4个字节
};
struct __attribute__((packed,aligned(4))) s2 {
char a; //1个字节
int i ; //4个字节
};
#pragma pack(1)
struct s3 {
char a; //1个字节
int i; //4个字节
char b; //1个字节
};
#pragma pack()
#pragma pack(4)
struct s4 {
char a; //1个字节
int i; //4个字节
char b; //1个字节
};
#pragma pack()
int main( int argc, char* argv[] )
{
int i;
struct s0 s_0; // 默认对齐
struct s1 s_1;
struct s2 s_2;
struct s3 s_3;
struct s4 s_4;
printf( " 默认对齐: sizeof s0 is %d\n" , sizeof(s_0) );
printf( "sizeof s1 is %d\n" , sizeof(s_1) );
printf( "sizeof s2 is %d\n" , sizeof(s_2) );
printf( "sizeof s3 is %d\n" , sizeof(s_3) );
printf( "sizeof s4 is %d\n" , sizeof(s_4) );
return( 0 );
}
tb@tb:~ gcc -o test test.c
tb@tb:~ ./test
最后的结果: