C語言內建函數:__builtin_XXX

 

首先內建函數有的屬於預編譯,有的屬於運行過程的函數,這一點我現在還不是很清楚,待以後進一步詳細討論。

然後我們給出一個長代碼,裏面包含了常用的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 
版權聲明:本文爲博主原創文章,轉載請附上博文鏈接!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章