#include <math.h>
#include <stdio.h>
int main()
{
printf("%f", roundf(3.14));
}
我编译上面的代码(没有使用-lm),添加使用ldd a.out,结果是
linux-vdso.so.1 => (0x00007fffab9ff000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd6da0f8000)
/lib64/ld-linux-x86-64.so.2 (0x00007fd6da4eb000)
为什么a.out没有链接 libm 但可以使用roundf(或类似sqrt)? 我使用nm来测试libc.so.6和ld-linux-x86064.so.2但是所有这些都没有roundf的符号。
我想知道roundf定义的位置,还是编译器内联? (用gcc 4.7.3和gcc 4.6.3测试)
答案是http://fedoraproject.org/w/index.php?title=UnderstandingDSOLinkChange
答案 0 :(得分:6)
作为优化,编译器会在编译时计算该值并使用常量,因此不会调用roundf()
。您可以通过查看生成的代码来验证这一点:
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $16, %esp
movl $.LC0, %eax
fldl .LC1
fstpl 4(%esp)
movl %eax, (%esp)
call printf
leave
ret
您可以看到生成的程序集中没有调用roundf()
。 (您可以使用gcc -S filename.c
生成此内容并读取生成的filename.s
文件。
答案 1 :(得分:1)
您在评论中提到libstdc++
,这让我怀疑问题在于您是与g++
而不是gcc
进行关联。
gcc
命令调用编译器和/或链接器。如果您使用它来编译源文件,它通常会确定语言(以及使用哪个编译器前端)。
g++
命令类似,但它专门用于C ++;如果它调用链接器,它会根据需要传递参数,以链接C ++所需的libstdc++
库。
例如,这两个命令只是在没有链接的情况下编译:
gcc -c foo.cpp
g++ -c foo.cpp
(据我所知)是等价的,但是这些命令:
gcc foo.cpp -o foo
g++ foo.cpp -o foo
不是;前者可能会失败(取决于foo.cpp
使用的功能)。
事实证明,与g++
命令不同,gcc
命令隐式链接数学库,至少在我的系统版本中。因此,如果您的C ++代码使用C ++特定的功能(例如,<iostream>
)和数学函数,那么将它与gcc
命令链接可能会产生对{{1}中定义的函数的抱怨}和libstdc++
- 这就是你所看到的。
如果您使用libm
命令进行链接,则可以解决问题。您可能需要修改您的g++
或等效内容,或者生成它的任何内容。
(如果这是解决方案,您应该将“c ++”添加到问题标签列表中。)
至于为什么你之前没遇到过这个问题,我说不出来。一些C(和/或C ++)编译器将隐式链接数学库;为其他编译器指定Makefile
的需要可能是一个错误。