GCC如何处理内置函数
我无法理解GCC内置函数,感到非常困惑。
-
库函数和内置函数有什么区别?
-
是否有内置函数可以做但库函数不能做?
-
我可以编写一个库函数来执行与内置函数printf相同的任务吗? 如何判断输入参数的类型(%f,float还是double)?
-
GCC内置函数的机器指令不存储在库中,对吧? 他们在哪?
-
在进行链接时,如何控制这些内置function代码的放置位置?
-
为什么有时我会在进行链接时出现错误消息,例如“未定义引用__builtin_stdarg_start”
// main.c #include int main(void) { printf("hello world!\n"); return 0; }
gcc -c main.c,nm表明main.o中没有符号printf,(只有main(T)和puts(U)),为什么?
库函数和内置函数有什么区别?
内置函数是编译器直接在编译器本身内部具有一些知识的函数。 库函数只是库中定义的函数。 可能存在内置函数和同名库函数,因此对于其余的问题,我将“库函数”视为“不是内置函数的库函数”。
是否有内置函数可以做但库函数不能做?
是。 例如,内置函数可以选择不评估其参数:
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
知识,但在大多数情况下,这是完全可行的。 查找如何使用
。
如何判断输入参数的类型(%f,float还是double)?
您必须信任调用者让格式字符串与其余参数匹配; 当格式字符串需要double
时,你无法检测到传递int
这样的东西。 但是你不需要处理float
和double
之间的区别,因为不可能将float
传递给printf
:它会在printf
看到它之前转换为double
(不管格式字符串如何)。 printf
的要求经过精心设计,以避免任何编译魔术的需要。
GCC内置函数的机器指令不存储在库中,对吧?
对内置函数的调用在编译时进行转换,但该转换可能只是调用同名库函数。
他们在哪?
如果转换在编译时完成,则没有机器指令。 将调用转换为不同的代码,然后编译该代码以生成机器指令。 如果结果是对库函数的调用,则该库函数的机器指令是库的一部分。
在进行链接时,如何控制这些内置函数代码的放置位置?
我不明白你的意思。 对内置函数的调用在编译时转换为不同的代码,然后将不同的代码编译为包含调用的函数的一部分。 它将放在包含函数的其余代码的任何位置。
为什么有时我会在进行链接时出现错误消息,例如“未定义引用__builtin_stdarg_start”
尽管有__builtin
前缀,但没有内置函数__builtin_stdarg_start
,因此将其视为对库函数的调用。 并且没有库函数__builtin_stdarg_start
,因此链接器会将此检测为错误。
曾经有一个内置函数__builtin_stdarg_start
,但它在几年前被删除了,代码从来没有应该首先使用它。
gcc -c main.c,nm表明main.o中没有符号printf,(只有main(T)和puts(U)),为什么?
那是因为printf
既作为内置函数又作为库函数存在。 内置函数通常只调用库函数,但有时可以做得更好,包括在您的示例中。 在这种情况下,内置函数printf
可以在不调用库函数printf
情况下提供正确的结果。
内置函数大致有两种:对应于标准库函数的内置函数(默认情况下, malloc
, printf
和strcpy
都被视为内置printf
),而标准库中没有对应函数的内置函数 -想想__builtin_expect
, __builtin_prefetch
等。
第一种内置函数可以使编译器发出优化代码来代替相应的调用。 知道来自标准库的每个调用的内部语义,编译器可以决定发出对驻留在库中的函数的调用,或者在其位置发出自定义生成的代码片段,以便原始语义保留,代码运行得更好。
第二种内置函数(也称为“内在函数”)支持使用驻留在库中的静态代码难以实现的技巧和优化。 它们可以转换为向CPU提供提示( __builtin_prefetch
, __builtin_expect
),或者通过更好的编译时内省( __builtin_constant_p
, __builtin_types_compatible_p
)来增强C语言,或者为某些特定于体系结构的指令提供更简单的,与平台无关的接口( __builtin_ffs
, __builtin_popcount
)。