gnu C语言__attribute__作用

关于attribute

在看linux源码的时候我们可能会经常碰见相关的东西,比如在dl_open的函数里边:

void* internal_function 
  _dl_open (const char *file, int mode, const void *caller)
  {
     struct dl_open_args args;

       __rtld_lock_lock_recursive (GL(dl_load_lock));

     args.file = file;
     args.mode = mode;
     args.caller = caller;
     args.map = NULL;

     dl_open_worker(&args);
        __rtld_lock_unlock_recursive (GL(dl_load_lock));

  }

这里的internal_function就是一个attribute的应用,其具体格式是:

#define internal_function __attribute__ ((regparm (3), stdcall))

attribute顾名思义,是说明函数(甚至是变量和结构体)的一些属性,这样给编译器提供更多的信息,我们在这里说明一些常用的attribute的用法。

注意

gnu cc需要用 -Wall来激活这个选项

用法

1 格式判断 format

说明:即按照格式字符串来判断参数的合法性,如果不合法则编译器给出warning
具体格式:attribute(format(type, string_index, first_to_check))
解释: type填scanf或者printf,表示用scanf或者printf的方式进行检测,string_index表示格式字符串是函数的第几个参数,最后first_to_check表示需要检查的参数位于函数的那个位置
示例:

void myPrint(const char* format_string, ...)
__attribute__(format(printf, 1, 2));//format_string是格式化字符串,后面的...是需要检测的参数
//格式化字符串位于第一个,而需要检测的参数位于函数的第二个,所以是format(printf, 1, 2)
//即string_index = 1, first_to_check = 2

2 函数不返回给调用者 noreturn

说明:表明该函数不需要返回给调用者,避免一些不必要的优化
具体格式:attribute((noreturn))
示例:

void myExit() __attribute__((noreturn));

3 const attribute

说明:这个属性主要用于没有静态状态和副作用的函数,其返回值主要依赖于输入值,且只能用于带有数值类型的函数,不能用于带有指针类型参数的函数
具体格式:attribute((const))
示例:

void intSqrt(int x)__attribute__((const))
//由于sqrt操作只依赖于x的输入,这样再调用相同的数值的时候会得到同样的输出,const就是针对这一类函数
//当重复调用同一个数值的时候,编译器会优化,使其只进行一次运算,而后来的调用都返回第一次的结果即可

4 no_instrument_function

说明:这个属性解释起来较为复杂,因为涉及到gcc的一个编译选项,-finstumat-function.添加了该参数,在编译的时候将会生成instrumentation调用,即在一个函数入口之后,和出口之前调用两个函数,分别是:

void __cyg_profile_func_enter(void *this_fn, void *call_site);
void __cyg_profile_func_exit(void *this_fn, void *call_site);
//profile函数

而不需要生成instrumentation调用的函数则使用该属性标明,典型的用法比如profile函数本身,高优先级的中断例程以及任何不能保证profiling正常调用的函数。
具体格式:attribute((no_instrument_function))
示例:

//test.c
#include 
void __cyg_profile_func_enter(void *, void *)
    __attribute__((no_instrument_function));
void __cyg_profile_func_exit(void *, void *)
    __attribute__((no_instrument_function));
void __cyg_profile_func_exit(void *this_fn, void *call_site)
{
    printf("this_func: %p call_addr: %p\n", this_fn, call_site);
}

void __cyg_profile_func_enter(void *this_fn, void *call_site)
{
    printf("this_func: %p call_addr: %p\n", this_fn, call_site);
}
int main()
{
    printf("hey, everybody!\n");
    return 0;
}

编译命令:

gcc -o test test.c -finstrument-functions

输出结果:(我是64位系统)

this_func: 0x400645 call_addr: 0x7feebbbd8f45
hey, everybody!
this_func: 0x400645 call_addr: 0x7feebbbd8f45

5 constructor/destructor属性

说明:主要用于对函数的初始化等,如果声明了constructor属性,则会在main函数之前执行,如果声明了destructor属性则会在main函数执行之后,或者exit被调用后自动执行。
具体格式:
attribute((constructor))
attribute((destructor))
示例:

//test.c
#include 
void constructor_func()
    __attribute__((constructor));
void destructor_func()
    __attribute__((destructor));
void constructor_func()
{
    printf("I am a constructor :)\n");
}
void destructor_func()
{
    printf("I am a destructor :)\n");
}
int main()
{
    printf("I am main, I did nothing! :(\n");
    return 0;
}

编译选项:

gcc -o test test.c

运行结果:

I am a constructor :)
I am main, I did nothing! :(
I am a destructor :)

6 变量属性

说明:之前我们提到的所有设置,都是对函数进行设置,这里,除了对函数进行设置,也可以对变量和结构体进行属性设置
常见变量属性:

  • aligned,指明对齐格式:int x[3] __attrubute__((aligned(16)))即16字节对齐。(使对象占用更多空间)
  • packed,使用最小对齐方式。int x[3] __attribute__((packed))(减少对象所占用空间)

在此我就不列出了,见更多变量属性。

7 类型属性

说明:就像变量属性是对变量的属性声明,类型属性就是对类型的属性声明。主要是对struct和union进行属性声明,这里不再赘述,和第6点比较类似,更多类型属性见此。

tips

  • attribute中的属性可以前后加双下划线以避免宏重复。
  • 可以用一个attribute指明多个属性,如__attrubute__((noreturn, format(printf, 1, 2))),当然也可以写多个attribute,如__attribute__((noreturn)) __attribute__((format(printf, 1, 2)))

你可能感兴趣的:(linux基础,C/C++)