いくつかの機能を見てみましょう。 gcc -O3 -c so.c
でコンパイル
#include <math.h>
double func(double num) {
return sqrt(num);
}
とobjdump -d so.o
で分解:ここでは最初のものだ
0000000000000000 <func>:
0: f2 0f 51 c8 sqrtsd %xmm0,%xmm1
4: 66 0f 2e c9 ucomisd %xmm1,%xmm1
8: 7a 05 jp f <func+0xf>
a: 66 0f 28 c1 movapd %xmm1,%xmm0
e: c3 retq
f: 48 83 ec 08 sub $0x8,%rsp
13: e8 00 00 00 00 callq 18 <func+0x18>
18: 48 83 c4 08 add $0x8,%rsp
1c: c3 retq
をだから我々は、FPUのレジスタ操作の束、およびコールを持っています。その呼び出しが何を呼び出すかを見てみましょう。 nm so.o
を実行します。
0000000000000000 T func
U sqrt
だから我々は(T
) "FUNC" と呼ばれる機能、およびインポート(U
)sqrt
と呼ばれるシンボルを定義しています。最終的なプログラムは、sqrt
が実際に定義されている通り、-lm
とリンクする必要があります。いいえFPUのレジスタ操作を
0000000000000000 <func>:
0: f2 0f 10 05 00 00 00 movsd 0x0(%rip),%xmm0 # 8 <func+0x8>
7: 00
8: c3 retq
を:gcc -O3 -c so.c
でコンパイルしないとobjdump -d so.o
で分解し、再び
#include <math.h>
double func() {
return sqrt(4);
}
:
今度は、第2の機能を試してみましょう。関数呼び出しはありません。 nm so.o
で確認しましょう:
0000000000000000 T func
0000000000000000 r .LC0
イエップ。記号のインポートはありません。
あなたが#include <math.h>
を省略した場合は、ここで何が起こっているかのヒントを得る:
$ gcc -O3 -g -c so.c
so.c: In function ‘func’:
so.c:2:10: warning: incompatible implicit declaration of built-in function ‘sqrt’
return sqrt(4);
^
sqrt
は、組み込み関数です。コンパイラはそれをいくつかの不透明な構造として扱いません。それはそれが何を理解します。後者の場合、コンパイラは実行時に関数を呼び出す必要はないことを理解しています。それはコンパイル中の答えが何であるかを知っています。それは返信用レジスタに回答を入れ、それを1日と呼びます。実行時間にsqrt
の呼び出しが含まれていないため、-lm
とリンクする必要はありません。
原因 'sqrt(4)'が2であることをコンパイラが知っているからです。最初のケースでは、 'gcc -O3 main.c -o main'を試してみてください。 – user3386109
ありがとう、兄さん! –