5
#include <math.h>
#include <stdio.h>
int main()
{
   printf("%f", roundf(3.14));
}

我编译上面的代码(没有使用-lm),添加use 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

4

2 回答 2

7

作为一种优化,编译器将在编译时计算该值并使用一个常量,因此不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

您可以看到生成的程序集中没有调用 to roundf()。(您可以生成它gcc -S filename.c并读取生成的filename.s文件)。

于 2013-04-25T00:29:28.063 回答
1

您在评论中提到libstdc++,这让我怀疑问题在于您链接的是 withg++而不是 with gcc

gcc命令调用编译器和/或链接器。如果您使用它来编译源文件,它通常会确定语言(以及使用哪个编译器前端)。

g++命令类似,但它专门用于 C++;如果它调用链接器,它会根据需要传递参数以链接libstdc++C++ 所需的库。

例如,这两个命令,无需链接即可编译:

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定义的函数的抱怨- 这正是您所看到的。libstdc++libm

如果您与g++命令链接,那应该可以解决问题。您可能必须修改您的Makefile或等效的,或生成它的任何东西。

(如果这是解决方案,您可能应该将“c++”添加到您问题的标签列表中。)

至于为什么你之前没有遇到这个问题,我说不出来。一些 C(和/或 C++)编译器会隐式链接数学库;需要-lm为其他编译器指定可以说是一个错误。

于 2013-04-25T01:16:16.250 回答