回答:
の関数stdlib.h
とにstdio.h
は実装がありlibc.so
(またはlibc.a
静的リンクの場合)、デフォルトで実行可能ファイルにリンクされます(-lc
指定されている場合と同様)。GCCは、-nostdlib
または-nodefaultlibs
オプションとのこの自動リンクを回避するように指示できます。
の数学関数にmath.h
はlibm.so
(またはlibm.a
静的リンク用)の実装libm
があり、デフォルトではリンクされていません。これlibm
/ libc
分割には歴史的な理由があり、どれも非常に説得力があります。
興味深いことに、C ++ランタイムにlibstdc++
はが必要libm
であるため、GCC(g++
)を使用してC ++プログラムをコンパイルすると、自動的にlibm
リンクされます。
Cは古い言語であり、FPUは比較的最近の現象であることを覚えておいてください。私が最初にCを見たのは8ビットプロセッサで、32ビットの整数演算さえも行うのは大変な作業でした。これらの実装の多くには、浮動小数点演算ライブラリさえありませんでした!
最初の68000マシン(Mac、Atari ST、Amiga)でさえ、浮動小数点コプロセッサはしばしば高価なアドオンでした。
浮動小数点演算をすべて行うには、かなり大きなライブラリが必要でした。そして、数学は遅くなるだろう。したがって、フロートを使用することはほとんどありません。整数またはスケーリングされた整数ですべてを実行しようとしました。math.hをインクルードする必要があるとき、歯を食いしばりました。多くの場合、それを回避するために独自の近似値とルックアップテーブルを作成します。
トレードオフは長い間存在していました。「fastmath」などと呼ばれる競合する数学パッケージが時々ありました。数学のための最良の解決策は何ですか?本当に正確だが遅いもの?不正確ですが高速ですか?トリガー関数の大きなテーブル?ほとんどの実装が明らかになるのは、コプロセッサーがコンピューター内にあることが保証されるまではありませんでした。組み込みのチップに取り組んでいて、数学の問題を処理するために数学ライブラリを組み込むかどうかを決定しようとしているプログラマーがいると思います。
それが数学が標準ではなかった理由です。多くの、またはおそらくほとんどのプログラムは、単一のフロートを使用しませんでした。FPUが常に使用されていて、浮動小数点数と倍精度浮動小数点数が常に操作するのに安価だったとしたら、「stdmath」があったことは間違いありません。
libm
がデフォルトでリンクされていない理由を説明していますが、数学はC89の標準であり、それ以前はK&Rが事実上標準化していたため、「stdmath」の発言は意味がありません。
誰も修正しようとしないとんでもない歴史的慣習のために。CとPOSIXに必要なすべての機能を単一のライブラリファイルに統合すると、この質問が何度も繰り返されるのを回避できるだけでなく、.so
リンクされた各ファイルにファイルシステム操作が必要になるため、動的リンク時に時間とメモリを大幅に節約できます。それを見つけて見つけるために、そして静的変数、再配置などのためのいくつかのページ
すべての機能が1つのライブラリとしているの実装-lm
、-lpthread
、-lrt
、などのオプションは一切-OPS(または空へリンクされていない.a
ファイル)が完全にされるPOSIXの準拠と確かに望ましいです。
注:C自体はコンパイラーの呼び出し方法について何も指定していないため、POSIXについて話しています。したがってgcc -std=c99 -lm
、準拠動作のためにコンパイラーを呼び出す必要がある実装固有の方法として扱うことができます。
strace
いずれかのタイミングオプションを使用して、動的リンクに費やされた起動時間を監視するか./configure
、すべての標準ユーティリティが静的リンクされているシステムと動的リンクされているシステムでの実行を比較します。主流のデスクトップアプリ開発者やシステムインテグレーターでさえ、動的リンクのコストを認識しています。これが、プレリンクのようなものが存在する理由です。これらの論文のいくつかでベンチマークを見つけることができると思います。
-lm
受け入れられる必要があり、数学インターフェイスを使用するアプリケーションはを使用する必要があります-lm
が、実際のライブラリファイルではなく、コンパイラコマンドによって処理される(または無視される)内部オプションの場合もあります。または.a
、インターフェースがメインlibcにある場合は、空のファイルにすることもできます。
strace -tt
動的リンクに費やされた時間を簡単に表示します。きれいじゃない。Linuxでは、検査/proc/sys/smaps
すると追加のライブラリのメモリオーバーヘッドが表示されます。
説明はここにあります:
したがって、プログラムが数学関数を使用してを含む
math.h
場合は、-lm
フラグを渡して数学ライブラリを明示的にリンクする必要があります。この特定の分離の理由は、数学者が数学の計算方法に非常にうるさく、標準の実装ではなく独自の数学関数の実装を使用したい場合があるためです。数学関数がlibc.a
それにまとめられていた場合、それを行うことはできません。
[編集]
しかし、私がこれに同意するかどうかはわかりません。たとえば、を提供するライブラリーがあり、sqrt()
それを標準ライブラリーの前に渡すと、Unixリンカーがバージョンを取得しますよね?
sqrt
と、動作が定義されていないプログラムになります。
-lm
は完全にオプションです。アイデア
外部ライブラリへのリンクについては、GCCの概要-外部ライブラリとのリンクで詳しく説明しています。ライブラリが標準ライブラリ(stdioなど)のメンバーである場合、それらをリンクするためにコンパイラ(実際にはリンカ)に指定する必要はありません。
編集:他のいくつかの回答とコメントを読んだ後、両方にリンクしているlibc.aリファレンスとlibmリファレンスには、なぜ2つが分離しているのかについて多くの説明があると思います。
「libm.a」(数学ライブラリ)の関数の多くは「math.h」で定義されていますが、libc.aにはありません。混乱を招く可能性のあるものもありますが、経験則としては、CライブラリにはANSIが規定する必要のある関数が含まれているため、ANSI関数のみを使用する場合は-lmは必要ありません。対照的に、 `libm.a 'はより多くの関数を含み、matherrコールバックやFPエラーの場合の動作のいくつかの代替標準への準拠などの追加機能をサポートします。詳細は、セクションlibmを参照してください。
sqrt
関数を使用するプログラムをコンパイルした理由を知っていますが、を介してライブラリを含めなくても機能し-lm
ます。ありがとう!
ephemientが言ったように、Cライブラリlibcはデフォルトでリンクされ、このライブラリにはstdlib.h、stdio.h、およびその他のいくつかの標準ヘッダーファイルの実装が含まれています。「GCCの概要」によると、Cの基本的な「Hello World」プログラムのリンカーコマンドは次のとおりです。
ld -dynamic-linker /lib/ld-linux.so.2 /usr/lib/crt1.o
/usr/lib/crti.o /usr/libgcc-lib /i686/3.3.1/crtbegin.o
-L/usr/lib/gcc-lib/i686/3.3.1 hello.o -lgcc -lgcc_eh -lc
-lgcc -lgcc_eh /usr/lib/gcc-lib/i686/3.3.1/crtend.o /usr/lib/crtn.o
Cライブラリをリンクする3行目のオプション-lcに注意してください。
それは一種の恣意的だと思います。どこかに線を引く必要があります(どのライブラリがデフォルトで、どのライブラリを指定する必要があるか)。
同じ機能を持つ別のものと交換する機会が与えられますが、そうすることはあまり一般的ではないと思います。
編集:(私のコメントから):gccは、元のccとの下位互換性を維持するためにこれを行うと思います。なぜccがこれを行うのかについての私の推測は、ビルド時間のためです-ccは、現在よりもはるかに少ない電力のマシン用に作成されました。多くのプログラムには浮動小数点演算機能がなく、おそらく一般的に使用されていないすべてのライブラリをデフォルトから除外しました。UNIX OSのビルド時間とそれに伴うツールが原動力だったと思います。
stdlib.hまたはstdio.hを配置した場合、それらをリンクする必要はありませんが、コンパイル時にリンクする必要があります。
stdlib.h
、stdio.h
ヘッダファイルがあります。あなたはあなたの便宜のためにそれらを含めます。適切なライブラリにリンクした場合にのみ、どのシンボルが利用可能になるかを予測します。実装はライブラリファイルにあります。これは、関数が実際に存在する場所です。
含めることmath.h
は、すべての数学関数にアクセスするための最初のステップにすぎません。
また、コンパイラーがシンボルについて情報を提供するだけの手順であるlibm
場合でも、その関数を使用しない場合は、リンクする必要はありません#include <math.h>
。
stdlib.h
、でstdio.h
使用可能な関数を参照してくださいlibc
。これはたまたまユーザーが自分で行う必要がないように常にリンクされています。
stdioは、デフォルトでgccがリンクする標準Cライブラリの一部です。
数学関数の実装は、デフォルトではリンクされない別個のlibmファイルにあるため、-lmを指定する必要があります。ちなみに、これらのヘッダーファイルとライブラリファイルとの間には何の関係もありません。
それをまったく使用しないアプリのパフォーマンスを少し向上させる方法だと思います。これは私の考えです。
x86 OS(および私は他の人も想像します)は、FPU状態をコンテキストスイッチに格納する必要があります。ただし、ほとんどのOSは、アプリが初めてFPUを使用しようとした後にのみ、この状態を保存/復元する必要があります。
これに加えて、ライブラリが読み込まれたときにFPUを正常な基本状態に設定する数学ライブラリにいくつかの基本的なコードが含まれている可能性があります。
そのため、数学コードをまったくリンクしない場合、これは発生しません。したがって、OSはFPU状態をまったく保存/復元する必要がないため、コンテキストスイッチがわずかに効率的になります。
ただ推測です。
編集:一部のコメントに応じて、同じ基本前提がFPU以外のケースにも適用されます(前提は、libmを使用しないアプリのパフォーマンスを少し向上させることでした)。
たとえば、Cの初期の段階でlikleyだったソフトFPUがある場合。libmを個別に設定すると、多くの大きな(使用されている場合は遅い)コードが不必要にリンクされるのを防ぐことができます。
さらに、使用可能な静的リンクのみがある場合、実行可能ファイルのサイズとコンパイル時間を短縮するという同様の議論が適用されます。