GNU C语法扩展(10)_内建函数


要研究LINUX内核,C语言是基础中的基础,但是LINUX并不是完全的标准C,而是对标准C做了很多扩展,这些扩展特性对于我们分析内核有着很重要的作用,下面做些总结性的工作。

10、内建函数

GNU C提供了大量的内建函数,其中很多是标准C库函数的内建版本,例如memcpy,它们与对应的C库函数功能相同,本文不讨论这类函数,其他内建函数的名字通常以__builtin开始。

  • 内建函数__builtin_return_address(LEVEL)​​返回当前函数或其调用者的返回地址,参数LEVEL指定调用栈的级数,如0表示当前函数的返回地址,1表示当前函数调用者的返回地址,依此类推。例
    如:
//kernel/sched.c
printk(KERN_ERR "schedule_timeout: wrong timeout" "value %lx from %p\n", timeout, __builtin_return_address(0));
  • 内建函数__builtin_constant_p(EXP)​用于判断一个值是否为编译时常数,如果参数EXP的值是常数,函数返回1,否则返回0。
//include /asm-i386/bitops.h
#define test_bit(nr,addr)/
(__builtin_constant_p(nr)?/
constant_test_bit( (nr),(addr) ):/
variable_test_bit( (nr),(addr) ) )

很多计算或操作在参数为常数时有更优化的实现,在GNUC中用上面的方法可以根据参数是否为常数,只编译常数版本或非常数版本,这样既不失通用性,又能在参数是常数时编译出最优化的代码。

  • 内建函数​__builtin_expect(EXP, C)​用于为编译器提供分支预测信息,其返回值是整数表达式EXP的值,C的值必须是编译时常数。例如:
//include /linux/compiler.h
#define likely(x) __builtin_expect((x),1)
#define unlikely(x) __builtin_expect((x),0)

//kernel/sched.c
if( unlikely(in_interrupt()) ){
printk("Schedulingininterrupt/n");
BUG();
}

这个内建函数的语义是EXP的预期值是C,编译器可以根据这个信息适当地重排语句块的顺序,使程序在预期的情况下有更高的执行效率。上面的例子表示处于中断上下文是很少发生的,第6-7行的目标码可能会放在较远的位置,以保证经常执行的目标码更紧凑。
若不想使用GNUC扩展,那么只需要在gcc参数后面加上-ansi-pedantic即可,使用上述参数后,所有GNCC扩展语法部分将会有编译警报。