1. 什么是 GCC 内建函数
GCC 内建函数(Built - in functions)是 GCC 编译器提供的一组特殊函数。这些函数不是标准 C 库或其他标准库的一部分,而是直接由编译器支持,它们被编译进程序代码中,就好像它们是普通的函数调用一样,但在某些情况下可以生成更高效的机器码。例如,一些内建函数可以直接利用处理器的特殊指令来执行操作,而不需要通过复杂的库函数调用过程。
2. 使用 GCC 内建函数的好处
- 性能优化:编译器可以针对内建函数进行特殊的优化,因为它清楚这些函数的具体行为。例如,对于一些频繁使用的操作,如内存复制或者位操作,内建函数可能会利用处理器的特殊指令集来加速执行,从而提高程序的整体性能。
- 与编译器紧密集成:内建函数能够更好地与编译器的其他功能配合。比如,在进行代码优化阶段,编译器可以对内建函数和其他代码一起进行优化,考虑到内建函数的特性,生成更高效的机器码。
- 方便进行错误检查:像__builtin_add_overflow这样的函数,可以帮助程序员方便地检查算术运算中的错误情况,如溢出等,这有助于编写更健壮的代码。
3. 常用的内联函数
3.1 算术运算相关内建函数
__builtin_add_overflow
- 简介:用于检测有符号整数加法是否溢出。它接受三个参数,前两个是相加的操作数,第三个是一个指向结果存储位置的指针。如果加法溢出,函数返回非零值,并将溢出后的值存储在第三个参数指向的位置;如果没有溢出,返回 0。
__builtin_sub_overflow
- 简介:和__builtin_add_overflow类似,但是用于检测有符号整数减法是否溢出。它检查第一个操作数减去第二个操作数是否会产生溢出情况。
__builtin_mul_overflow
- 简介:用于检测有符号整数乘法是否溢出。在进行乘法运算时,通过这个函数可以判断结果是否超出了有符号整数的表示范围。
__builtin_umaddl_overflow
- 简介:针对无符号整数乘法和加法组合操作(a * b + c)检测溢出。这在处理高精度计算或者需要考虑运算结果范围的情况下非常有用。
__builtin_saddl_overflow
- 简介:用于检测长整型(long int)加法是否溢出,和__builtin_add_overflow功能类似,但操作数类型为长整型。
__builtin_ssubl_overflow
- 简介:用于检测长整型减法是否溢出,和__builtin_sub_overflow功能类似,针对长整型操作数。
__builtin_smull_overflow
- 简介:用于检测长整型乘法是否溢出,和__builtin_mul_overflow功能类似,不过是用于长整型。
3.2 内存操作相关内建函数
__builtin_memcpy
- 简介:执行内存复制操作,类似于标准 C 库中的memcpy函数。它可以将一段内存中的数据复制到另一段内存中,并且编译器可能会对其进行优化,提高内存复制的效率。
__builtin_memmove
- 简介:功能类似于__builtin_memcpy,但在源和目标内存区域重叠的情况下,__builtin_memmove能保证正确地复制数据,而memcpy的行为在这种情况下是未定义的。
__builtin_memset
- 简介:用于将一段内存区域设置为指定的值。通常用于初始化数组或者清除内存中的数据,比手动循环设置内存单元更高效。
__builtin___memcpy_chk
- 简介:是一种带有边界检查的内存复制函数。它在复制内存的同时会检查目标缓冲区的大小是否足够,以防止缓冲区溢出错误。
__builtin___memset_chk
- 简介:类似__builtin___memcpy_chk,是带有边界检查的内存设置函数,确保设置内存操作不会超出缓冲区范围。
3.3 位操作相关内建函数
__builtin_popcount
- 简介:计算一个无符号整数中设置为1的位的数量。例如,对于二进制数1011,它会返回3,因为这个数中有3个1。该函数在处理位掩码等操作时很有用。
__builtin_popcountl
- 简介:和__builtin_popcount类似,但操作数是unsigned long类型,用于计算无符号长整数中1的位数。
__builtin_clz
- 简介:计算无符号整数二进制表示中前导0的数量。例如,对于二进制数000101,它会返回3,因为前面有3个0。这个函数在处理位对齐等操作时很有帮助。
__builtin_ctz
- 简介:计算无符号整数二进制表示中尾随0的数量。比如对于二进制数10100,它会返回2,因为末尾有2个0。
__builtin_ffs
- 简介:返回x的最后一位1的是从后向前第几位,比如7368(1110011001000)返回4。
__builtin_parity
- 简介:返回x的奇偶校验位,也就是x的1的个数模2的结果。等效于__builtin_popcount(x) & 1。
3.4 类型转换相关内建函数
__builtin_bswap16/__builtin_bswap32/__builtin_bswap64
- 简介:这些函数分别用于交换 16 位、32 位和 64 位整数的字节顺序。在处理网络协议或者不同字节序的文件格式等场景中非常有用。例如,在网络通信中,数据通常是以大端序(高位字节在前)传输的,而某些处理器可能是小端序(低位字节在前)存储数据,通过这些函数可以方便地进行字节序转换。
__builtin_types_compatible_p
- 简介:用于检查两个类型是否兼容。它是一个编译时求值的函数,返回一个整数,1表示两个类型兼容,0表示不兼容。这在编写通用代码或者模板代码时,对于类型检查很有帮助。
3.5 函数调用相关内建函数
__builtin_call_with_args
- 简介:这是一个比较复杂的内建函数,用于以特定的参数调用另一个函数。它在一些高级的代码生成场景或者对函数调用进行动态处理时可能会用到,不过使用频率相对较低。
__builtin_apply_args和__builtin_apply
- 简介:这两个函数一起用于实现一种类似于函数指针调用的机制,同时还可以处理可变数量的参数。它们在实现一些复杂的函数调用逻辑,特别是涉及到可变参数列表和动态函数调用的情况下很有用。
3.6 其他杂项内建函数
__builtin_return_address
- 简介:用于获取当前函数的返回地址。这在调试或者某些需要跟踪函数调用链的场景下可能会用到。不过需要注意的是,在一些优化级别下,返回地址可能会因为内联等操作而不准确。
__builtin_frame_address
- 简介:返回当前函数的栈帧地址。栈帧是函数调用过程中在栈上分配的一块内存区域,用于存储函数的局部变量、参数和返回地址等信息。这个函数可以帮助在调试或者分析栈相关的问题时获取有用的信息。
__builtin_expect
- 简介:用于给编译器提供分支预测的提示。它接受两个参数,第一个是一个表达式,第二个是一个预期的值(通常是0或者1)。编译器可以根据这个提示来优化分支指令,提高程序的执行效率。例如,如果一个条件分支经常为真,通过__builtin_expect告知编译器后,编译器可以将更可能执行的代码路径放在更靠近处理器的分支预测单元的位置。
__builtin_constant_p
- 简介:用于判断一个表达式是否在编译时为常量。这在编写宏或者模板代码时,对于区分常量和变量表达式很有用,可以根据这个判断来进行不同的代码生成策略。
__builtin_alloca
- 简介:用于在栈上动态分配内存。与malloc等函数不同,__builtin_alloca分配的内存是在当前函数的栈帧上,当函数返回时自动释放。这在需要临时分配一些小的内存空间,且不希望手动管理内存释放的情况下很有用。
__builtin_nan/__builtin_inf
- 简介:分别用于创建非数字(NaN)和无穷大(inf)的值。在处理浮点数运算,特别是涉及到数学库函数或者特殊数学概念(如极限)的场景下可能会用到这些函数。
4. Built in相关的compiler options
-fbuiltin
- 这是默认选项,用于通过名字来识别内建函数
-fno-builtin
- 除非利用前缀 _builtin 进行引用,否则不识别所有内建函数。例如,为了获得内建版本,应该调用 __builtin_strcpy() 而不是名为 strcpy() 的函数。
-fno-builtin-xxx
- 例如:-fno-builtin-sqrt:想使用除sqrt() 之外的所有内建函数