attribute属性

attribute属性

__attribute__介绍

attribute的格式.

__attribute__((attribute-list))

attribute属性可以在编译的时候告诉编译器函数, 结构体的属性是什么, 进行某些编译优化, 也可以提供更加准确的错误检查.

attribute是GNU特有的特性

这里主要说明attribute的4个属性, 分别是packed, aligned, constructor, destructor.

packed属性

设置结构体和类的对齐方式, 它使得变量和结构体,类按最小对齐方式来对齐变量.

我们直接写

struct Temp
{
    char j;
    int i;
}temp;
struct Attribute_t
{
    char i;
    int j;
}__attribute__((packed))attribute_t;

在这里插入图片描述

可以看出来, attribute是最小对齐, 中间没有任何空的内存, 而没有使用的结构体是严格按照规定的对齐方式来对齐数据的. 这种对齐在内核代码里面最常见, 很多的结构体希望尽量的小, 节约内存空间, 就会用到packed属性, x86源码就特别常见的.

aligned属性

aligned属性跟packed有些相反, aligned是可以自己设置对齐的大小, 格式为

__attribute__((aligned)); 	// 默认属性, 编译器自动设置对齐大小
__attribute__((aligned(n)));	// n为自己设置的对齐大小

编写例子来看

struct Temp
{
    char i;
    int j;
}__attribute__((aligned)) temp;
struct Attribute_t
{
    char i;
    int j;
    int t;
}__attribute__((aligned(8))) attribute_t;

在这里插入图片描述

可以看到temp的默认属性, 设置的是16字节对齐, 我们设置aligned(8)是按照8字节进行对齐. 之所有attribute多了一个变量是为了字节大小超过8字节, 对齐后才是16字节.

而设置对齐的意义在于

  1. aligned后面不紧跟一个指定的数字值,编译器将依据你的目标机器情况使用最大最有益的对齐方式。选择针对目标机器最大的对齐方式,可以提高拷贝操作的效率.
  2. 自己手动设置对齐方式可以调整内存空间的位置

constructor属性

设置了这个属性的函数将会在main函数开始之前执行.

我们可以来尝试一下 , 设置了这个属性是不是真的在main函数开始执行之前执行的.

__attribute__((constructor)) void print()
{
    printf("first\n");
}
int main()
{
    printf("last\n");
    exit(0);
}

在这里插入图片描述

事实就是这样. 当然, 我们探索也不会这样简单的结束啊, 要看看在那里调用了设置了属性的函数

objdump a.out

在这里插入图片描述

上面是设置属性的ATT汇编, 下面是去掉设置属性的ATT汇编

在这里插入图片描述

可以看出来, 设置属性的在编译期间设置将其函数加入到 .init的.init_array数组中. 其实是加入了ELF中的.ctorsdtors中, 并且对齐函数设置了优先级, 此优先级比main函数的优先级高, 程序开始的时候是先执行优先级高的, 所以是从在main函数开始之前就执行了.

destructor属性

destructor属性是在exit()函数执行之后执行. 这个是exit调用之后运行, 可以来做一个实验来验证是exit之后执行.

void exit_()
{
	printf("exit\n");
}

__attribute__((destructor)) void fun()
{
    printf("attributor\n");
}

int main()
{
    printf("main\n");
    atexit(exit_);
    exit(0);
}

在这里插入图片描述

可以看出来设置属性的要在exit之后才执行, 至于atexit()函数有兴趣的可以了解一下, 这里的exit(0)不能替换成_exit函数, 想尝试的也可以试一下, 这里大概讲一下为什不能用_exit函数.

exit函数在执行的时候会先执行atexit再执行其他清理步骤, 而设置属性的相当于析构函数, 在exit执行完清理进入内核之前执行, 而_exit函数则是不进行任何清理处理, 而是直接的进入内核, 不会调用析构函数, 所以根本不会触发设置属性的函数.


参考于 :

__attribute__机制介绍

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值