【问题标题】:How GCC handles built-in functionGCC 如何处理内置函数
【发布时间】:2014-05-29 09:56:30
【问题描述】:

对 GCC 的内置函数理解有困难,感到很困惑。

  • 库函数和内置函数有什么区别?

  • 有没有内置函数可以做而库函数不能做的事情?

  • 我可以编写一个库函数来执行与内置函数 printf 相同的任务吗?如何判断输入参数的类型(%f、float 或 double)?

  • GCC 内置函数的机器指令不存储在库中,对吧?他们在哪里?

  • 在链接的时候,如何控制这些内置函数代码的放置位置?

  • 为什么有时我会在链接时出现错误消息,例如“未定义对 __builtin_stdarg_start 的引用”

    // main.c
    #include <stdio.h>
    int main(void) {
      printf("hello world!\n");
      return 0;
    }
    

    gcc -c main.c, nm 显示main.o中没有符号printf,(只有main(T)和puts(U)),为什么?

【问题讨论】:

  • (用T称为内置)
  • 您可以创建自己的 printf。查看 stdargs.h 标头。
  • GCC (很可能)将您的printf() 优化为puts(),因为您只是将一个简单的字符串传递给printf(),而没有任何进一步的参数。见:linux.die.net/man/3/puts
  • 对于 mem* 和 str* 函数,GCC 似乎主要在大小恒定时使用 '_builtin' 进行优化(在编译时已知)

标签: c++ c gcc


【解决方案1】:

库函数和内置函数有什么区别?

内置函数是编译器直接在编译器内部了解的函数。库函数只是在库中定义的函数。同名的内置函数和库函数可能都存在,所以对于您的其余问题,我会将“库函数”视为“不是内置函数的库函数”。

有没有内置函数可以做而库函数不能做的事情?

是的。例如,内置函数可以选择不评估其参数:

int main() {
  int i = 0;
  __builtin_constant_p (++i); // checks whether ++i is a constant expression
                              // does not evaluate ++i
  return i; // returns 0
}

这是因为编译器可以将内置函数转换为其他东西,实际上不需要包含任何函数调用。

我可以编写一个库函数来执行与内置函数 printf 相同的任务吗?

printf 有一些内置知识,但在大多数情况下,这是完全可行的。查看&lt;stdarg.h&gt;的使用方法。

如何判断输入参数的类型(%f、float 或 double)?

你必须信任调用者让格式字符串匹配剩余的参数;当格式字符串需要 double 时,您无法检测到像传递 int 这样的东西。但是您不需要处理floatdouble 之间的区别,因为不可能将float 传递给printf:它将在@ 之前转换为double(无论格式字符串如何) 987654331@ 看到了。 printf 的要求是经过精心设计的,以避免需要任何编译器魔法。

GCC 内置函数的机器指令不存储在库中,对吧?

对内置函数的调用在编译时进行转换,但这种转换可能只是导致对同名库函数的调用。

他们在哪里?

如果转换是在编译时完成的,则没有机器指令。该调用被转换为不同的代码,然后该代码被编译以产生机器指令。如果结果是调用库函数,则该库函数的机器指令是库的一部分。

在链接的时候,如何控制这些内置函数代码的放置位置?

我不明白你在这里的意思。对内置函数的调用在编译时转换为不同的代码,然后将不同的代码编译为包含调用的函数的一部分。它将被放置在该包含函数的其余代码将放置的任何位置。

为什么有时我会在链接时出现错误消息,例如“未定义对 __builtin_stdarg_start 的引用”

没有内置函数__builtin_stdarg_start,尽管有__builtin 前缀,所以这被视为对库函数的调用。并且也没有库函数__builtin_stdarg_start,因此链接器将其检测为错误。

曾经有一个内置函数__builtin_stdarg_start,但它在几年前就被删除了,代码从一开始就不应该使用它。

gcc -c main.c, nm 显示main.o中没有符号printf,(只有main(T)和puts(U)),为什么?

这是因为printf 既作为内置函数又作为库函数存在。内置函数通常只是简单地调用库函数,但有时可以做得更好,包括在您的示例中。在这种情况下,内置函数printf可以在不调用库函数printf的情况下给出正确的结果。

【讨论】:

    【解决方案2】:

    内置函数大致有两种:对应标准库函数的(mallocprintfstrcpy默认都被视为内置函数)和不对应的。在标准库中没有对应物 - 想想__builtin_expect__builtin_prefetch 等。

    第一种内置函数使编译器能够发出优化代码来代替相应的调用。了解标准库中每个调用的内部语义后,编译器可以决定要么发出对驻留在库中的函数的调用,要么发出自定义生成的代码片段,以便原始语义被保留并且代码运行得更好。

    第二种内置函数(也称为“intrinsics”)可以实现一些技巧和优化,而这些技巧和优化是使用库中的静态代码难以实现的。它们可能会转化为向 CPU 提供提示(__builtin_prefetch__builtin_expect),或者通过更好的编译时自省来增强 C 语言(__builtin_constant_p__builtin_types_compatible_p),或者提供更简单、独立于平台的接口一些特定于架构的指令(__builtin_ffs__builtin_popcount)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-02-17
      • 1970-01-01
      • 2012-05-28
      • 2017-01-09
      • 2015-03-08
      • 2013-12-16
      • 1970-01-01
      • 2013-04-18
      相关资源
      最近更新 更多