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

roundf()生成されたアセンブリに への呼び出しがないことがわかります。(これを使用して生成しgcc -S filename.c、生成されたファイルを読み取ることができfilename.sます)。

于 2013-04-25T00:29:28.063 に答える
1

あなたはコメントで言及しましlibstdc++たが、問題はあなたが.g++gcc

このgccコマンドは、コンパイラおよび/またはリンカーを呼び出します。これを使用してソース ファイルをコンパイルすると、通常は言語 (したがって、使用するコンパイラ フロントエンド) が決定されます。

g++コマンドは似ていますが、C++ に特化しています。libstdc++リンカーを呼び出す場合、必要に応じて、C++ に必要なライブラリをリンクするために引数を渡します。

たとえば、次の 2 つのコマンドは、リンクせずにコンパイルするだけです。

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 に答える