绪
__attribute__
是GUN C
中极具特设的一大机制,可以用来设置
- 函数属性(Function Attribute)
- 变量属性(Variable Attribute)
- 类型属性(Type Attribute)
这里我们主要阐述用__attribute__((aligned(n)))
和__attribute__((packed))
两个指令对结构体进行属性设置
一、作用简述
__attribute__((aligned(n))) //采用n字节对齐
__attribute__((packed)) //采用1字节对齐
其中
__attribute__((aligned(n)))
中,n
的有效参数为2的幂值,32位最大为2 ^ 32,64位为2 ^ 64
,这个时候编译器会将让n
与默认的对齐字节数进行比较,取较大值为对齐字节数,与#pragma pack(n)
恰好相反。__attribute__((packed))
则为取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐,也就是采用1字节对齐。
二、在结构体类型中的使用方法
2.1 使用格式
/*定义结构体时不对类型重命名*/
struct mystruct
{
/*成员变量定义*/
}__attribute__() /*(可同时在这定义变量)*/;
struct __attribute__() mystruct
{
/*成员变量定义*/
}/*(可同时在这定义变量)*/;
/*定义结构体同时对类型进行重命名*/
typedef struct mystruct
{
/*成员变量定义*/
}__attribute__() MS;
typedef struct __attribute__() mystruct
{
/*成员变量定义*/
}MS;
2.2 测试代码
#include <stdio.h>
typedef struct mystruct1
{ //in64_64 in32_32
int a; //(4 + 4) 4
double b;// 8 8
char c; //(1 + 15) (1 + 3)
}__attribute__((aligned(16))) AMS1;//in 64_64:32; in 32_32:16
typedef struct __attribute__((aligned(16))) mystruct2
{ //in64_64 in32_32
int a; //(4 + 4) 4
double b;// 8 8
char c; //(1 + 15) (1 + 3)
}AMS2; //in 64_64:32; in 32_32:16
struct mystruct3
{
int a;
double b;
char c;
}__attribute__((aligned(16))) test3;
struct __attribute__((aligned(16))) mystruct4
{
int a;
double b;
char c;
}test4;
typedef struct mystruct5
{
int a; //4
double b;//8
char c; //1
}__attribute__((packed)) PMS5;//in 64_64:13; in 32_32:13
typedef struct mystruct6
{ //in64_64 in32_32
int a; //(4 + 4) 4
double b;// 8 8
char c; //(1 + 7) (1 + 3)
}__attribute__((aligned(8))) A8MS6;//in 64_64:24; in 32_32:16
typedef struct mystruct7
{ //in64_64 in32_32
int a; //(4 + 4) 4
double b;// 8 8
char c; //(1 + 7) (1 + 3)
}__attribute__((aligned(2))) A2MS7;//in 64_64:24; in 32_32:16
typedef struct mystruct8
{ //in64_64 in32_32
int a; //(4 + 4) 4
double b;// 8 8
char c; //(1 + 15) (1 + 19)
}__attribute__((aligned(32))) A32MS8;//in 64_64:32; in 32_32:32
int main(void)
{
AMS1 test1;
AMS2 test2;
printf("sizeof(test1) = %d\n", (int)sizeof(test1));
printf("sizeof(test2) = %d\n", (int)sizeof(test2));
printf("sizeof(test3) = %d\n", (int)sizeof(test3));
printf("sizeof(test4) = %d\n", (int)sizeof(test4));
printf("sizeof(PMS5) = %d\n", (int)sizeof(PMS5));
printf("sizeof(A8MS6) = %d\n", (int)sizeof(A8MS6));
printf("sizeof(A2MS7) = %d\n", (int)sizeof(A2MS7));
printf("sizeof(A32MS8) = %d\n", (int)sizeof(A32MS8));
return 0;
}
2.3 测试结果
其中,test1~test4
主要进行格式的测试。对于__attribute__((aligned(16)))
,对齐图示如下(文字描述参照代码中的注释):
对于其他的n
也是这样分析:
- 在64位操作系统64位编译器的环境下,当n ≥ 8时,内存对齐的字节数是n,不然为8
- 在32位操作系统32位编译器的环境下,当n ≥ 4时,内存对齐的字节数是n,不然为4
由PMS5
也可以看出,__attribute__((packed))
就是一字节对齐
三、aligned(n)
在变量、函数中的使用
3.1 在变量中的使用
C/C++中长度为n字节的基本数据类型的变量在编译时会被编译器默认分配到n字节对齐的内存上。例如,int的长度是4字节,所以int类型变量将被分配到4字节对齐的地址上。我们也可以通过__attribute__((aligned(n)))
来改变这种默认状态。
int a __attribute__ ((aligned (16))) = 0;
这样就把a
分配到了16
字节对齐的地址上。
3.2在函数中的使用
和改变变量的默认对齐状态一样,也可以通过__attribute__((aligned(n)))
来改变函数的自然对齐状态。
void __attribute__ ((aligned (64))) func(void)
{
/*功能实现代码*/
}
关于__attribute__
这里只浅显地总结这么一点东西,如果需要更加丰富的内容,请查阅:
GCC手册:使用GUN编译器集合(GCC)类型属性