GCC -fno-builtin & 内建函数

-fno-builtin

-fno-builtin 是 GCC 编译器的一个选项。下面,让我们来深入了解它。

当使用 GCC 编译代码时,编译器知道很多标准的库函数(例如 strcpy, memcpy, printf 等)。当优化代码时,如果 GCC 看到这些函数的使用,并且可以确定它们的语义,它可能会替换它们为更有效率的代码版本,或者直接内联它们的功能,而不是进行函数调用。这是因为 GCC 内部有这些函数的“内建”版本(built-in)。

使用 -fno-builtin 选项可以告诉编译器不要为任何函数做这样的替换,即使编译器知道这些函数的语义。换句话说,当使用这个选项时,所有的函数调用,包括那些 GCC 知道的标准库函数,都会被保留,不会被替换为内建版本。

为什么使用 -fno-builtin?

  1. 测试和调试:可能正在写一个操作系统或其他低级程序,而这样的代码可能会提供自己的版本的某些标准库函数。在这种情况下,我们可能不希望编译器自动替换它们。

  2. 确保行为:有时,内建函数的行为可能与特定版本的标准库函数略有不同。使用 -fno-builtin 可以确保我们的代码调用的是真正的库函数,而不是编译器的内建版本。

  3. 移植性:在某些情况下,特定的编译器优化可能会导致代码在某些平台上不能正常工作。禁用内建函数可以帮助识别和避免这种情况。

总的来说,除非有特定的原因,大多数应用程序代码不需要使用 -fno-builtin 选项。但在特定的上下文和用例中,它可以是一个有用的工具。

GCC 的内建函数

GCC 的内建函数(built-in functions)是特定于编译器的优化实现,它们为常用的操作提供了高效的实现方式。这些内建函数经常被用于替代标准库中的常用函数。当编译器在代码中遇到这些函数,并且可以确定它们的语义时,GCC 会尝试用更优化的版本替代它们,或者根据上下文进行其他优化。

以下是内建函数的一些关键点:

  1. 性能优化:许多内建函数的实现都经过了优化,以利用特定平台或架构的功能。例如,对于某些内存操作,GCC 可能会选择使用特定的CPU指令来加速操作。

  2. 函数替换:当识别到代码中使用了某些标准库函数(例如 memcpy, strlen 等)时,GCC 会考虑使用内建函数版本替代这些调用,从而提供更高效的代码。

  3. 内联扩展:对于某些简单的函数,GCC 的内建版本可能直接在调用位置内联实现,从而消除函数调用的开销。

  4. 特定功能:除了替代标准库函数外,GCC 还提供了一系列特定于编译器的内建函数,用于执行不常见或特定于平台的操作,例如 __builtin_expect(用于提供分支预测信息)和 __builtin_popcount(计算一个整数中设置的位数)。

  5. 默认行为:除非使用了诸如 -fno-builtin-fno-builtin-function-name(其中 function-name 是特定函数的名称)这样的编译器选项,否则GCC 默认会尝试使用内建函数。

  6. 独立于库:内建函数的另一个重要特点是它们不依赖于任何运行时库[1]。这意味着,即使没有链接相应的C库,内建函数也可以工作。这在如裸机编程或特定的嵌入式系统上下文中特别有用。

总之,GCC 的内建函数是编译器提供的一组工具,旨在增强性能和为程序员提供更多功能。然而,了解它们的存在和如何使用它们是很重要的,特别是在性能敏感或资源受限的应用中。


注[1]:当我们谈到“内建函数”,我们实际上是在谈论 GCC 编译器内部的优化和功能。为了进一步解释,我们先了解一下通常情况下编译和链接的过程。

在常规的编程中:

  1. 我们写了代码并保存为 .c 文件。
  2. 使用编译器,如 GCC,将 .c 文件编译为目标文件(.o.obj 文件)。
  3. 然后,我们会链接这些目标文件以及其他必要的库,生成一个可执行文件。

当我们在代码中调用一个标准库函数,例如 printf,这个函数的实际代码通常位于一个运行时库中(例如在 C 中为 libc)。在链接过程中,这些函数会被包括进我们的应用程序,使得它们在运行时可以被调用。

但对于 GCC 的内建函数来说,情况有所不同:

当 GCC 看到诸如 memcpy 这样的标准函数调用,并认为使用其内建版本会更优化时,它会直接在编译时把那些函数调用替换为特定的、经过优化的代码。这意味着:

  1. 这个代码不再是一个“函数调用”到某个库,而是直接嵌入到程序中的实际代码。
  2. 由于不再需要外部的函数调用,程序也不需要依赖于包含那个函数的运行时库。

这种行为的优点包括:

  1. 性能:由于不需要进行函数调用,这种直接替换通常更快。
  2. 独立性:程序不再依赖于外部的运行时库,这在嵌入式编程、裸机编程或任何其他需要避免额外依赖的场景中非常有用。

但这也意味着,如果我们显式地要求 GCC 不使用特定的内建函数(例如通过 -fno-builtin-memcpy),那么在链接时必须提供一个包含 memcpy 的库,否则链接器会报错说找不到该函数。

总之,GCC 的内建函数功能允许它在编译时替换掉某些标准库函数调用,生成更快、更小、不依赖特定运行时库的代码。

你可能感兴趣的:(编译原理,编译原理)