Cpp位运算函数-__builtin_
命运最迷人的地方从来都不是你生下来就有什么,而是你改变的那一部分~
__builtin_
系列函数是 GCC 提供的一些内置函数,旨在优化位运算和其他低级操作。这些函数通常直接映射到底层硬件指令,使得某些操作更为高效。以下是一些常用的位运算相关的 __builtin_
函数及其示例:
__builtin_popcount
/__builtin_popcountl
/__builtin_popcountll
-
功能: 计算整数的二进制表示中
1
的个数(即汉明重量)。 -
示例: 假设我们需要统计一个整数的二进制表示中有多少个
1
。1
2
3
4
5
6
7
8
int main() {
unsigned int x = 0b110110; // 二进制表示:110110
int count = __builtin_popcount(x);
std::cout << "Number of 1s in " << x << " is: " << count << std::endl;
return 0;
}输出:
1
Number of 1s in 54 is: 4
解释:
110110
中有四个1
。
__builtin_ctz
/__builtin_ctzl
/__builtin_ctzll
-
功能: 计算整数二进制表示下从右往左数连续
0
的个数(Count Trailing Zeros)。 -
示例: 找出一个整数尾部连续
0
的数量。1
2
3
4
5
6
7
8
int main() {
unsigned int x = 0b1001000; // 二进制表示:1001000
int trailing_zeros = __builtin_ctz(x);
std::cout << "Number of trailing zeros in " << x << " is: " << trailing_zeros << std::endl;
return 0;
}输出:
1
2
Number of trailing zeros in 72 is: 3解释:
1001000
尾部有三个0
。
__builtin_clz
/__builtin_clzl
/__builtin_clzll
-
功能: 计算整数二进制表示下从左往右数的前导
0
的个数(Count Leading Zeros)。 -
示例: 找出一个整数前导连续
0
的数量。1
2
3
4
5
6
7
8
int main() {
unsigned int x = 0b00001000; // 二进制表示:00001000
int leading_zeros = __builtin_clz(x);
std::cout << "Number of leading zeros in " << x << " is: " << leading_zeros << std::endl;
return 0;
}输出:
1
2
Number of leading zeros in 8 is: 28解释: 对于 32 位整数,
00001000
前导有 28 个0
。
__builtin_parity
/__builtin_parityl
/__builtin_parityll
-
功能: 计算整数二进制表示中
1
的个数的奇偶性。如果1
的个数是奇数,返回1
;否则返回0
。 -
示例: 检查整数的奇偶性。
1
2
3
4
5
6
7
8
int main() {
unsigned int x = 0b1011; // 二进制表示:1011
int parity = __builtin_parity(x);
std::cout << "Parity of " << x << " is: " << parity << std::endl;
return 0;
}输出:
1
2
Parity of 11 is: 1解释:
1011
中有三个1
,为奇数,故返回1
。
__builtin_bswap16
/__builtin_bswap32
/__builtin_bswap64
-
功能: 交换字节顺序,用于大小端转换。
-
示例: 将
32
位整数的字节顺序进行交换。1
2
3
4
5
6
7
8
int main() {
uint32_t x = 0x12345678;
uint32_t swapped = __builtin_bswap32(x);
std::cout << "Original: 0x" << std::hex << x << ", Swapped: 0x" << swapped << std::endl;
return 0;
}输出:c
1
2
Original: 0x12345678, Swapped: 0x78563412解释:
0x12345678
经过字节顺序交换变为0x78563412
。
__builtin_ffs
/__builtin_ffsl
/__builtin_ffsll
-
功能: 找到整数中最低位
1
的位置,返回从1
开始的位置索引,如果没有找到则返回0
。 -
示例: 找到整数中最低位
1
的位置。1
2
3
4
5
6
7
8
int main() {
int x = 0b101000; // 二进制表示:101000
int position = __builtin_ffs(x);
std::cout << "First set bit in " << x << " is at position: " << position << std::endl;
return 0;
}输出:
1
2
First set bit in 40 is at position: 4解释:
101000
中最低位的1
在第4
位。7.
__builtin_frame_address
使用了 __builtin_frame_address(0)
来获取当前栈帧的栈指针地址。不同的编译器可能有不同的方式获取栈指针地址。
1 |
|
栈指针与栈区的关系
- 栈指针(Stack Pointer, SP)是一个寄存器,它持有当前栈顶的地址。每个线程都有自己的栈指针,这个指针在函数调用、局部变量分配等操作时不断变化。
- 栈区是线程独立的内存区域,用于存储该线程的局部变量、函数调用信息等。栈指针指向当前线程栈区的顶部。
8.__builtin_expect
分支预测优化,这是现代处理器用来提高程序执行效率的一种技术。
在现代处理器中,当遇到一个分支(如 if-else
)时,处理器会尝试“猜测”哪个分支更有可能被执行,并提前加载该分支的指令以减少等待时间。这种“猜测”被称为分支预测。
- 预测正确:处理器可以直接执行已加载的指令,提升效率。
- 预测错误:处理器需要丢弃已经加载的指令,重新加载正确分支的指令,这会导致性能损失。
__builtin_expect
的作用
__builtin_expect
是 GCC 和 Clang 编译器提供的一个内建函数,用来显式告诉编译器某个条件更可能为真或假,从而帮助编译器优化分支预测。
__builtin_expect(!!(x), 1)
:表示x
更可能为true
。__builtin_expect(!!(x), 0)
:表示x
更可能为false
。
在你的代码中:
1 | #define likely(x) __builtin_expect(!!(x), 1) |
likely(x)
:表示x
更可能为真。unlikely(x)
:表示x
更可能为假。
1 | bool stealTask(UTaskWrapperRef task) { |
在这个例子中,unlikely(pool_threads_->size() < CGRAPH_DEFAULT_THREAD_SIZE)
表示线程池未初始化完毕的情况是极少发生的。
- 目的:告诉编译器,这个
if
条件极少会成立(即false
的概率非常高),因此编译器可以优化为更倾向于执行else
分支(即return true;
的部分)。 - 好处:编译器可以根据这个提示,优化指令的预加载顺序,以更好地适应实际运行时的情况,减少分支预测错误带来的开销。
4. !!(x)
的作用
!!(x)
的作用是将 x
转换为布尔值:
- 第一个
!
将x
转换为false
或true
的相反值。 - 第二个
!
再次取反,将其转换回true
或false
。
所以 !!(x)
就是为了确保 x
被转换为 bool
类型。这在一些情况下很有用,因为你希望传递给 __builtin_expect
的是真正的布尔值,而不是某个可以隐式转换为 bool
的值。
总结
__builtin_
系列函数是 C++ 中非常高效的位运算工具,能显著提高特定操作的性能。通过这些示例,我们可以看到它们在各种实际应用场景中的效果