GCC提供的builtin函数
杨开凤
GCC提供了⼀系列的builtin函数,可以实现⼀些简单快捷的功能来⽅便程序编写,另外,很多builtin函数可⽤来优化编译结果。这些函数以“_builtin”作为函数名前缀。
很多C标准库函数都有与之对应的GCC builtin函数,例如strcpy()有对应的__builtin_strcpy()内建函数。
下⾯就介绍⼀些builtin函数及其作⽤:
__builtin_ffs(x):返回x中最后⼀个为1的位是从后向前的第⼏位,如__builtin_ffs(0x789)=1, __builtin_ffs(0x78c)=3。于是,__builtin_ffs(x) - 1就是x中最后⼀个为1的位的位置。
__builtin_popcount(x):x中1的个数。
__builtin_ctz(x):x末尾0的个数。x=0时结果未定义。
__builtin_clz(x):x前导0的个数。x=0时结果未定义。
注意:
上⾯的宏中x都是unsigned int型的,如果传⼊signed或者是char型,会被强制转换成unsigned int。
__builtin_parity(x):x中1的奇偶性。
__builtin_return_address(n):当前函数的第n级调⽤者的地址,⽤的最多的就是__builtin_return_address(0),即获得当前函数的调⽤者的地址。注意,该函数实现是体系结构相关的,有些体系结构只实现了n=0的返回结果。
uint16_t __builtin_bswap16 (uint16_t x)、 uint32_t __builtin_bswap32 (uint32_t x):按字节翻转x,返回翻转后的结果。
__builtin_prefetch (const void *addr, …):它通过对数据⼿⼯预取的⽅法,在使⽤地址addr的值之前就将其放到cache中,减少了读取延迟,从⽽提⾼了性能,但该函数也需要 CPU 的⽀持。该函数可接受三个参数,第⼀个参数addr是要预取的数据的地址,第⼆个参数可设置为0或1(1表⽰我对地址addr要进⾏写操作,0表⽰要进⾏读操作),第三个参数可取0-3(0表⽰不⽤关⼼时间局部性,取完addr的值之后便不⽤留在cache中,⽽1、2、3表⽰时间局部性逐渐增强)。
__builtin_constant_p (exp):判断exp是否在编译时就可以确定其为常量,如果exp为常量,该函数返回1,否则返回0。如果exp为常量,可以在代码中做⼀些优化来减少处理exp的复杂度。
__builtin_types_compatible_p(type1, type2):判断type1和type2是否是相同的数据类型,相同返回1,否则返回0。该函数不区分const/volatile这样的修饰符,即int和const int被认为是相同的类型。
鲁迅原名什么字什么名字#define foo(x)
({
typeof(x) tmp = (x);\
if(__builtin_types_compatible_p(typeof(x), int))\
//\
el \
腊肉炒青椒的做法//\
tmp;
})
初中生打架__builtin_expect (long exp, long c):⽤来引导gcc进⾏条件分⽀预测。在⼀条指令执⾏时,由于流⽔线的作⽤,CPU可以完成下⼀条指令的取指,这样可以提⾼CPU的利⽤率。在执⾏⼀条条件分⽀指令时,CPU也会预取下⼀条执⾏,但是如果条件分⽀跳转到了其他指令,那CPU预取的下⼀条指令就没
⽤了,这样就降低了流⽔线的效率。内核中的likely()和unlikely()就是通过__builtin_expect来实现的。
__builtin_expect (long exp, long c)函数可以优化程序编译后的指令序列,使指令尽可能的顺序执⾏,从⽽提⾼CPU预取指令的正确率。该函数的第⼆个参数c可取0和1,
例如:
if (__builtin_expect (x, 0))
射雕英雄传人物foo ();
表⽰x的值⼤部分情况下可能为0,因此foo()函数得到执⾏的机会⽐较少。gcc就不必将foo()函数的汇编指令紧挨着if条件跳转指令。由于第⼆个参数只能取整数,所以如果要判断指针或字符串,可以像下⾯这样写:
if (__builtin_expect (ptr != NULL, 1))
foo (*ptr);
表⽰ptr⼀般不会为NULL,所
以foo函数得到执⾏的概率较⼤,gcc会将foo函数的汇编指令放在挨着if跳转执⾏的位置。
使⽤实例:
__builtin_ctz(x); // 求x的⼆进制数末尾0的个数促销商品
__builtin_ctz(0100) == 2;
__builtin_clz(x); // 求x的⼆进制数前导0的个数(ps:⼀共有32位)
__builtin_clz(0100) == 29;
__builtin_popcount(x); // 求x的⼆进制数中的1的个数
__builtin_popcount(0100) == 1;
__builtin_ffs(x); // 求x的⼆进制数中最低位1的位置(突然发现和lowbit有⼀样的作⽤,但是要⽐lowbit慢)柏拉图表格
太阳的资料__builtin_ffs(0100) == 3;
__builtin_parity(x); // 求x的⼆进制数中1的个数的奇偶性(奇数为1 偶数为0)
__builtin_parity(0100) == 1;