Cプログラムに<stdlib.h>
または<stdio.h>
を含める場合、コンパイル時にこれらをリンクする必要はありませんが、gccで<math.h>
を使用して、-lm
にリンクする必要があります。次に例を示します。
gcc test.c -o test -lm
この理由は何ですか?他のライブラリではなく、数学ライブラリを明示的にリンクする必要があるのはなぜですか?
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は比較的最近の現象であることを思い出してください。私は最初に8ビットプロセッサでCを見ましたが、32ビットの整数演算でさえ多くの作業が必要でした。これらの実装の多くは、浮動小数点演算ライブラリを使用できるを持っていませんでした!
最初の68000マシン(Mac、Atari ST、Amiga)でも、多くの場合、浮動小数点コプロセッサーは高価なアドオンでした。
すべての浮動小数点演算を行うには、かなり大きなライブラリが必要でした。そして、数学は遅くなるだろう。したがって、フロートはほとんど使用しませんでした。整数またはスケーリングされた整数ですべてを実行しようとしました。 math.hをインクルードしなければならなかったとき、歯を痛めた。多くの場合、独自の近似値とルックアップテーブルを作成して回避します。
トレードオフは長い間存在していました。時々、「fastmath」などと呼ばれる競合する数学パッケージがありました。数学の最良の解決策は何ですか?本当に正確だが遅いもの?不正確だが速い?トリガー関数の大きなテーブル?ほとんどの実装が明らかになったのは、コンピューターにコプロセッサーが存在することが保証されるまでではありませんでした。組み込みのチップに取り組んで、数学の問題を処理するために数学ライブラリを取り込むかどうかを決定しようとしているプログラマーがどこかにいると思います。
それが数学がstandardでなかった理由です。多くのまたはおそらくほとんどのプログラムは、単一のフロートを使用しませんでした。 FPUが常に存在し、フロートとダブルが常に安価に動作していた場合、「stdmath」があったことは間違いありません。
誰も直そうとしないばかげた歴史的慣習のために。 CとPOSIXに必要なすべての機能を単一のライブラリファイルに統合すると、この質問が何度も聞かれるのを回避できるだけでなく、各.so
ファイルが動的リンクのときに時間とメモリを大幅に節約できますリンクには、ファイルシステムの操作が必要であり、それを見つけて見つける必要があります。また、静的変数、再配置などのために数ページ必要です。
すべての関数が1つのライブラリにあり、-lm
、-lpthread
、-lrt
などのオプションがすべてノーオペレーション(または空の.a
ファイルへのリンク)である実装完全にPOSIX準拠であり、確かに望ましい。
注:C自体はコンパイラーの起動方法について何も指定しないため、POSIXについて説明しています。したがって、gcc -std=c99 -lm
を、準拠動作のためにコンパイラを呼び出す必要がある実装固有の方法として扱うことができます。
time()
と他のいくつかの関数はbuiltin
がCライブラリ(libc
)自体とGCCで定義されているためalways libcへのリンクnless-ffreestanding
コンパイルオプションを使用します。ただし、数学関数はlibm
にあり、gccによって暗黙的にリンクされていません。
説明が与えられます ここ :
したがって、プログラムで数学関数を使用し、
math.h
を含める場合は、-lm
フラグを渡して数学ライブラリを明示的にリンクする必要があります。この特定の分離の理由は、数学者が数学の計算方法に非常にこだわりがあり、標準実装の代わりに数学関数の独自の実装を使用する場合があるためです。数学関数がlibc.a
にまとめられている場合、それを行うことはできません。
[編集]
ただし、これに同意するかどうかはわかりません。たとえばsqrt()
を提供するライブラリがあり、それを標準ライブラリの前に渡すと、Unixリンカーがバージョンを取得しますか?
Ephemientが言ったように、Cライブラリlibcはデフォルトでリンクされており、このライブラリにはstdlib.h、stdio.h、および他のいくつかの標準ヘッダーファイルの実装が含まれています。追加するだけで、「 An Introduction to 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の概要-外部ライブラリとのリンク に、外部ライブラリへのリンクの詳細な説明があります。ライブラリが標準ライブラリ(stdioなど)のメンバーである場合、それらをリンクするためにコンパイラ(実際にはリンカ)に指定する必要はありません。
編集:他の回答とコメントのいくつかを読んだ後、私は libc.a reference とそれが両方にリンクするlibmリファレンスには、なぜこれら2つが別々であるかについて多くのことを述べていると思います。
'libm.a'(数学ライブラリ)の関数の多くは 'math.h'で定義されていますが、libc.aには存在しないことに注意してください。混乱を招く可能性のあるものもありますが、大雑把に言えば、CライブラリにはANSIが指定する必要がある関数が含まれているため、ANSI関数のみを使用する場合は-lmは必要ありません。対照的に、 `libm.a 'にはより多くの関数が含まれており、matherrコールバックやFPエラーの場合の動作のいくつかの代替標準への準拠などの追加機能をサポートしています。詳細については、セクションlibmを参照してください。
Arbitrary意的だと思います。どこかに線を引く必要があります(どのライブラリがデフォルトで、どのライブラリを指定する必要があるか)。
同じ機能を持つ別のものに置き換える機会を与えてくれますが、そうすることはあまり一般的ではないと思います。
編集:(私自身のコメントから):gccはオリジナルのccとの後方互換性を維持するためにこれを行うと思います。 ccがこれを行う理由についての私の推測は、ビルド時間のためです。ccは、現在よりもはるかに少ない電力のマシン用に記述されています。多くのプログラムには浮動小数点演算がなく、通常使用されていないすべてのライブラリをデフォルトから使用している可能性があります。 UNIX OSのビルド時間とそれに付随するツールが原動力だったと思います。
Stdlib.hまたはstdio.hを配置した場合、それらをリンクする必要はありませんが、コンパイル時にリンクする必要があります。
stdlib.h
、stdio.h
はヘッダーファイルです。あなたの便宜のためにそれらを含めます。適切なライブラリにリンクした場合にのみ、どのシンボルが利用可能になるかを予測します。実装はライブラリファイルにあり、関数が実際に存在します。
math.h
を含めることは、すべての数学関数にアクセスするための最初のステップにすぎません。
また、シンボルに関するコンパイラーのための情報ステップである#include <math.h>
を実行する場合でも、その関数を使用しない場合はlibm
に対してリンクする必要はありません。
stdlib.h
、stdio.h
は、libc
で使用可能な関数を参照します。これは、ユーザーが自分で行う必要がないように、常にリンクされています。
stdioは、デフォルトでgccがリンクする標準Cライブラリの一部です。
数学関数の実装は、デフォルトではリンクされていない別のlibmファイルにあるため、-lmを指定する必要があります。ところで、これらのヘッダーファイルとライブラリファイルの間に関係はありません。
guessまったく使用しないアプリのパフォーマンスをわずかに向上させる方法だと思います。これについての私の考えは次のとおりです。
x86 OS(および私は他の人も想像します)は、コンテキストスイッチでFPU状態を保存する必要があります。ただし、ほとんどのOSは、アプリが初めてFPUを使用しようとした後、この状態を保存/復元するだけです。
これに加えて、数学ライブラリにはおそらく、ライブラリがロードされたときにFPUを正常な基本状態に設定する基本的なコードがいくつかあります。
したがって、数学コードをまったくリンクしなければ、これは発生しません。したがって、OSはFPUの状態をまったく保存/復元する必要がなく、コンテキストスイッチをわずかに効率的にします。
ただ推測。
編集:いくつかのコメントに応じて、同じ基本前提がまだFPU以外のケースに適用されます(前提は、libmを使用しないアプリをわずかに優れたものにすることでした)。
たとえば、Cの初期にリクリーであったソフトFPUがある場合、libmを分離すると、大量の(使用された場合は遅い)コードが不必要にリンクされるのを防ぐことができます。
さらに、静的リンクのみが利用可能な場合、実行可能ファイルのサイズとコンパイル時間を短縮するという同様の引数が適用されます。