Cで数学ライブラリをリンクする必要があるのはなぜですか?
-
06-07-2019 - |
質問
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
はリンクされません。このlibc
/ libstdc++
分割には歴史的な理由がありますが、説得力のあるものはありません。
興味深いことに、C ++ランタイムg++
には<=>が必要なので、GCC(<=>)を使用してC ++プログラムをコンパイルすると、自動的に<=>がリンクされます。
他のヒント
Cは古い言語であり、FPUは比較的最近の現象であることを思い出してください。私は最初に8ビットプロセッサでCを見ましたが、32ビットの整数演算でさえ多くの作業が必要でした。これらの実装の多くは、浮動小数点演算ライブラリを使用することもできませんでした!
最初の68000マシン(Mac、Atari ST、Amiga)でも、多くの場合、浮動小数点コプロセッサーは高価なアドオンでした。
すべての浮動小数点演算を行うには、かなり大きなライブラリが必要でした。そして、数学は遅くなるだろう。したがって、フロートはほとんど使用しませんでした。整数またはスケーリングされた整数ですべてを実行しようとしました。 math.hをインクルードしなければならなかったとき、歯を痛めた。多くの場合、独自の近似値とルックアップテーブルを作成して回避します。
トレードオフは長い間存在していました。時々、<!> quot; fastmath <!> quotと呼ばれる競合する数学パッケージがありました。またはそのような。数学の最良の解決策は何ですか?本当に正確だが遅いもの?不正確だが速い?トリガー関数の大きなテーブル?ほとんどの実装が明らかになったのは、コンピューターにコプロセッサーが存在することが保証されるまでではありませんでした。今どこかにプログラマーがいて、組み込みチップに取り組んでいて、数学の問題を処理するために数学ライブラリを取り込むかどうかを決定しようとしていると思います。
だからこそ、数学は 標準 ではありませんでした。多くのまたはおそらくほとんどのプログラムは、単一のフロートを使用しませんでした。 FPUが常に存在し、floatとdoubleの操作が常に安価であれば、<!> quot; stdmath <!> quot;。
があったことは間違いありません。誰も直そうとしないばかげた歴史的慣習のため。 CとPOSIXが必要とするすべての機能を単一のライブラリファイルに統合すると、この質問が何度も聞かれるのを回避できるだけでなく、リンクされた各.so
ファイルが必要になるため、動的リンクの際にかなりの時間とメモリも節約できますそれを見つけて見つけるためのファイルシステム操作、およびその静的変数、再配置などのための数ページ。
すべての関数が1つのライブラリにあり、-lm
、-lpthread
、-lrt
などのオプションがすべてノーオペレーション(または空の.a
ファイルへのリンク)である実装は、完全にPOSIX準拠であり、確かに望ましい。
注:C自体はコンパイラの起動方法について何も指定しないため、POSIXについて説明しています。したがって、適合動作のためにコンパイラを呼び出す必要がある実装固有の方法としてgcc -std=c99 -lm
を扱うことができます。
time()
および他の一部の関数はbuiltin
Cライブラリ(libc
)自体で定義されているため、GCCはlibcへの常にリンクを使用します -ffreestanding
コンパイルオプション。ただし、数学関数はgccによって暗黙的にリンクされていないlibm
にあります。
説明がここにあります:
したがって、プログラムで数学関数を使用し、
math.h
を含める場合は、-lm
フラグを渡して数学ライブラリを明示的にリンクする必要があります。この特定の分離の理由は、数学者が数学の計算方法に非常にこだわりがあり、標準実装の代わりに数学関数の独自の実装を使用する場合があるためです。数学関数がlibc.a
にまとめられている場合、それを行うことはできません。
[編集]
しかし、これに同意するかどうかはわかりません。たとえば、sqrt()
を提供するライブラリがあり、それを標準ライブラリの前に渡すと、Unixリンカーがバージョンを取得しますか?
ephemientが言ったように、Cライブラリlibcはデフォルトでリンクされ、このライブラリにはstdlib.h、stdio.h、および他のいくつかの標準ヘッダーファイルの実装が含まれています。 <!> quot; GCCの紹介 <!> quot;基本的な<!> quot; Hello World <!> quotのリンカコマンド。 Cのプログラムは次のとおりです。
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リファレンスとそれが両方にリンクしている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
を含めることは、すべての数学関数にアクセスするための最初のステップにすぎません。
また、その関数を使用しない場合は、libm
をリンクする必要はありません。シンボルについてのコンパイラーに対して、単なる情報ステップである#include <math.h>
を実行しても、
libc
、<=>は、<=>で使用可能な機能を指します。これは、常にリンクされているため、ユーザーが自分で行う必要はありません。
stdioは、デフォルトでgccがリンクする標準Cライブラリの一部です。
数学関数の実装は、デフォルトではリンクされていない別のlibmファイルにあるため、-lmを指定する必要があります。ところで、これらのヘッダーファイルとライブラリファイルの間に関係はありません。
まったく使用しないアプリのパフォーマンスをわずかに向上させる方法であることを推測します。これについての私の考えです。
x86 OS(および私は他の人も想像します)は、コンテキストスイッチでFPU状態を保存する必要があります。ただし、ほとんどのOSは、アプリが初めてFPUを使用しようとした後、この状態の保存/復元のみを行います。
これに加えて、おそらく数学ライブラリには、ライブラリがロードされたときにFPUを正常な基本状態に設定する基本的なコードがいくつかあります。
したがって、数学コードをまったくリンクしない場合、これは発生しません。したがって、OSはFPUの状態をまったく保存/復元する必要がなく、コンテキストスイッチをわずかに効率的にします。
ただの推測。
編集:一部のコメントに応じて、FPU以外の場合にも同じ基本前提が適用されます(libmを使用しないアプリをわずかに実行することを前提としています)より良い)。
たとえば、Cの初期にリクリーであったソフトFPUがある場合、libmを分離することで、大量の(使用された場合は遅い)コードが不必要にリンクされるのを防ぐことができます。
さらに、利用可能な静的リンクのみがある場合、実行可能ファイルのサイズとコンパイル時間を短縮するという同様の引数が適用されます。