为什么它不需要链接libm?

时间:2013-04-25 00:25:19

标签: c++ c gcc libm

#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

2 个答案:

答案 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的需要可能是一个错误。