首先內建函數有的屬於預編譯,有的屬於運行過程的函數,這一點我現在還不是很清楚,待以後進一步詳細討論。
然後我們給出一個長代碼,裏面包含了常用的C語言內建函數,參考文章見文末。
總覽:
- __builtin_ffs(s);
- __builtin_popcount(s);
- __builtin_ctz(s);
- __builtin_clz(s);
- __builtin_parity(i);
- __builtin_return_address(s);
- __builtin_bswap16(i);
- __builtin_bswap32(i);
- __builtin_prefetch(const void *addr, ...);
- __builtin_constant_p(exp);
- __builtin_types_compatible_p(t1, t2);
- __builtin_expect(exp, c);
#include <stdio.h>
#include <stdarg.h>
/**
* 返回x中最後一個爲1的位是從後向前的第幾位
* 000101000 -> 4
* 8 -> 4
*/
#define ffs(s) __builtin_ffs(s)
/**
* x中1的個數
*
*/
#define popcount(s) __builtin_popcount(s)
/**
* x末尾0的個數。x=0時結果未定義。
* x前導0的個數。x=0時結果未定義。
*/
#define ctz(s) __builtin_ctz(s)
#define clz(s) __builtin_clz(s)
/**
* x中1的奇偶性。
* 奇:1, 偶:0
*/
#define parity(i) __builtin_parity(i)
/**
* 當前函數的第n級調用者的地址,用的最多的就是__builtin_return_address(0),
* 即獲得當前函數的調用者的地址。
* 注意,該函數實現是體系結構相關的,有些體系結構只實現了n=0的返回結果。
*/
#define return_addr(s) __builtin_return_address(s)
void test1_return_address(){printf("%s: %p\n", __func__, return_addr(1));}
void test2_return_address(){test1_return_address(); printf("%s: %p\n", __func__, return_addr(0));}
void test3_return_address(){test2_return_address(); printf("%s: %p\n", __func__, return_addr(0));}
/**
* 按字節翻轉x,返回翻轉後的結果。
* uint16_t __builtin_bswap16 (uint16_t x)
* uint32_t __builtin_bswap32 (uint32_t x)
*/
#define swap16(i) __builtin_bswap16(i)
#define swap32(i) __builtin_bswap32(i)
/**
* 它通過對數據手工預取的方法,在使用地址addr的值之前就將其放到cache中,
* 減少了讀取延遲,從而提高了性能,但該函數也需要 CPU 的支持。
* 該函數可接受三個參數,
* 第一個參數addr是要預取的數據的地址,
* 第二個參數可設置爲0或1(1表示我對地址addr要進行寫操作,0表示要進行讀操作),
* 第三個參數可取0-3(0表示不用關心時間局部性,取完addr的值之後便不用留在cache中,
* 而1、2、3表示時間局部性逐漸增強)。
* __builtin_prefetch (const void *addr, ...)
*/
#define prefetch(...) __builtin_prefetch(__VA_ARGS__)
/**
* 判斷exp是否在編譯時就可以確定其爲常量,
* 如果exp爲常量,該函數返回1,否則返回0。
* 如果exp爲常量,可以在代碼中做一些優化來減少處理exp的複雜度
*/
#define constant_p(exp) __builtin_constant_p(exp)
#define CONST_P 123
/**
* 判斷type1和type2是否是相同的數據類型,相同返回1,否則返回0。
* 該函數不區分const/volatile這樣的修飾符,即int和const int被認爲是相同的類型
*/
#define types_cmp_p(t1, t2) __builtin_types_compatible_p(t1, t2)
#if 0
#define foo(x) \
typeof(x) tmp = (x);\
if(__builtin_types_compatible_p(typeof(x), int))\
//do something...\
else \
//do something...\
tmp;
#endif //0
/**
* 用來引導gcc進行條件分支預測。在一條指令執行時,由於流水線的作用,
* CPU可以完成下一條指令的取指,這樣可以提高CPU的利用率。
* 在執行一條條件分支指令時,CPU也會預取下一條執行,但是如果條件分支跳轉到了其他指令,
* 那CPU預取的下一條指令就沒用了,這樣就降低了流水線的效率。
* 內核中的likely()和unlikely()就是通過__builtin_expect來實現的。
* __builtin_expect (long exp, long c)函數可以優化程序編譯後的指令序列,
* 使指令儘可能的順序執行,從而提高CPU預取指令的正確率。該函數的第二個參數c可取0和1,
*/
#define except(exp, c) __builtin_expect(exp, c)
#define likely(x) __builtin_expect(!!x, 1)
#define unlikely(x) __builtin_expect(!!x, 0)
int main()
{
int i = 0x03f8;
printf("%d, %d, %d, %d\n", ffs(i), popcount(i), ctz(i), clz(i));
printf("%d\n", parity(i));
printf("main: %p\n", main);
test3_return_address();
printf("%x, %x\n", i, swap32(i));
prefetch(&i, 0, 2);
printf("%p\n", &i);
printf("constant: %d\n", constant_p(CONST_P));
printf("constant: %d\n", constant_p(i));
int j;
printf("type cmp: %d\n", types_cmp_p(typeof(j), typeof(i)));
if(likely(i))
printf("likely:%ld, %d\n", likely(i), i);
return 0;
}
/**
https://blog.csdn.net/jasonchen_gbd/article/details/44948523
*/
作者:落塵紛擾
來源:CSDN
原文:https://blog.csdn.net/jasonchen_gbd/article/details/44948523
版權聲明:本文爲博主原創文章,轉載請附上博文鏈接!