上篇文章:ARM 嵌入式 编译系列 4.2 – GCC 链接规范 extern “C“ 介绍
下篇文章:ARM 嵌入式 编译系列 6 – GCC objcopy, objdump, readelf, nm 介绍
什么是GCC内建函数?
GCC提供了一些专门的功能,用于访问特定的硬件指令或者实现特定的优化,它们被称为"__builtin
"函数。
这些函数在语法上看起来像是普通函数,但在编译阶段会被编译器直接转换为一些特定的机器指令,而不是像普通函数那样调用通用的函数调用协议。
GCC提供的__builtin
函数非常多,包括了数学函数、字符串操作、内存操作、位操作、类型转换、计数前导零/尾零、CPU指定指令等等功能。
使用__builtin
函数可以在不牺牲可读性的同时获得更高的性能。但是请注意,由于这些函数直接对应特定的硬件指令,所以在不同的硬件和操作系统上,它们的效果和性能可能会有所不同。因此,在编写依赖于__builtin
函数的代码时,需要特别注意移植性的问题。
要在GCC中使用__builtin
函数,只需要在代码中直接调用即可,无需包含任何头文件。
GCC 常见内建函数
GCC编译器提供了很多内建函数,这些函数可以帮助我们进行一些特殊的操作,以下是一些常见的GCC内建函数:
-
__builtin_expect
:提供编译器关于一个条件判断表达式结果的预期值,用于优化代码, 见likely
与unlikely
的实现; -
__builtin_clz
:计算无符号整数的前导零的数量; -
__builtin_ctz
:计算无符号整数的尾随零的数量; -
__builtin_popcount
:计算二进制表示中1的个数; -
__builtin_types_compatible_p
:在编译期检查两个类型是否兼容; -
__builtin_offsetof
:获取结构体成员在结构体中的偏移量; -
__builtin_prefetch
:预先把数据加载到缓存,用于提高程序运行效率; -
__builtin_return_address
:获取返回地址,常用于调试; -
__builtin_frame_address
:获取当前函数调用栈帧的地址; -
__builtin_choose_expr
:在编译期进行条件选择。
以上只是GCC内建函数的一部分,GCC还提供了许多其他的内建函数。这些内建函数都是在编译期间执行,因此它们不能用于运行时的计算。同时,由于这些函数是编译器提供的,所以它们的行为可能会随着编译器的版本和目标平台的不同而有所变化。
GCC内建函数使用示例
以下为一些GCC内建函数的使用示例:
__builtin_expect
if (__builtin_expect(x > 0, 1))
{
//大部分情况下,x > 0
} else {
//其他情况
}
__builtin_clz
unsigned int x = 16;
int leading_zero = __builtin_clz(x); // 结果为 27
__builtin_ctz
unsigned int x = 16;
int trailing_zero = __builtin_ctz(x); // 结果为 4
__builtin_popcount
unsigned int x = 15;
int count_one = __builtin_popcount(x); // 结果为 4
__builtin_offsetof
struct S {
int x;
double y;
};
size_t offset = __builtin_offsetof(struct S, y); // 结果为 sizeof(int)
__builtin_prefetch
int array[100];
__builtin_prefetch(&array[50], 0, 0);
// ... 其他代码 ...
int data = array[50]; // 这个读取操作可能会更快,因为数据可能已经在缓存中
以上只是简单示例,实际应用中可能需要根据具体情况调整使用方式。
由于__builtin
函数是GCC
特有的扩展,所以如果你的代码需要在其他编译器(如Clang、MSVC等)上编译,那么可能需要提供相应的兼容代码。对于这种情况,GCC也提供了一些预处理宏,可以用来检查当前编译器是否支持__builtin
函数。例如:
#ifdef __GNUC__
int clz = __builtin_clz(42);
#else
// 提供一个备用的实现
int clz = fallback_clz(42);
#endif
总的来说,__builtin
函数是GCC提供的一种强大的工具,可以在需要的时候用来提高代码的性能。但是,由于它们的移植性问题,所以在使用时需要谨慎。
上篇文章:ARM 嵌入式 编译系列 4.2 – GCC 链接规范 extern “C“ 介绍
下篇文章:ARM 嵌入式 编译系列 6 – GCC objcopy, objdump, readelf, nm 介绍