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++ 中非常高效的位运算工具,能显著提高特定操作的性能。通过这些示例,我们可以看到它们在各种实际应用场景中的效果





