Cの数学ライブラリをリンクする必要があるのはなぜですか?


254

Cプログラムに組み込ん<stdlib.h>だり<stdio.h>、Cプログラムに組み込んだりする場合、コンパイル時にこれらをリンクする必要はありませんが、たとえばgcc <math.h>を使用-lmしてにリンクする必要があります。

gcc test.c -o test -lm

これの理由は何ですか?数学ライブラリを明示的にリンクする必要があるのに、他のライブラリをリンクする必要がないのはなぜですか?

回答:


249

の関数stdlib.hとにstdio.hは実装がありlibc.so(またはlibc.a静的リンクの場合)、デフォルトで実行可能ファイルにリンクされます(-lc指定されている場合と同様)。GCCは、-nostdlibまたは-nodefaultlibsオプションとのこの自動リンクを回避するように指示できます。

の数学関数にmath.hlibm.so(またはlibm.a静的リンク用)の実装libmがあり、デフォルトではリンクされていません。これlibm/ libc分割には歴史的な理由があり、どれも非常に説得力があります。

興味深いことに、C ++ランタイムにlibstdc++はが必要libmであるため、GCC(g++)を使用してC ++プログラムをコンパイルすると、自動的にlibmリンクされます。


8
これはLinuxよりずっと前から一般的であったため、Linuxとは関係ありません。数学関数を必要としないプログラムがたくさんあるので、実行可能ファイルのサイズを最小化しようとすることと関係があるのではないかと思います。
David Thornley、

39
古代のシステムでは、数学関数がlibcに含まれていた場合、すべてのプログラムのコンパイルが遅くなり、出力実行可能ファイルが大きくなり、ランタイムはより多くのメモリを必要とし、これらの数学関数をまったく使用しないほとんどのプログラムにはメリットがありませんでした。最近は共有ライブラリが十分にサポートされており、静的にリンクしている場合でも、標準ライブラリは未使用のコードを破棄できるように設定されているため、これらの理由はもはや正当な理由ではありません。
ephemient 2009年

38
@ephemient昔のように、ライブラリにリンクしても、ライブラリのすべてのコンテンツが実行可能ファイルに取り込まれませんでした。リンカーは、しばしば無視される技術ですが、歴史的には非常に効率的でした。

7
@ephemientまた、共有ライブラリは、思ったよりもずっと昔から存在しています。それらは1980年代ではなく、1950年代に発明されました。

5
結局のところ、私たちが見ているのは、GCCの保守主義に過ぎないと思います。「常にそのように機能しています」。私は彼らがコンパイラの拡張機能に同じ理由を適用したいだけです。

77

Cは古い言語であり、FPUは比較的最近の現象であることを覚えておいてください。私が最初にCを見たのは8ビットプロセッサで、32ビットの整数演算さえも行うのは大変な作業でした。これらの実装の多くに、浮動小数点演算ライブラリさえありませんでした!

最初の68000マシン(Mac、Atari ST、Amiga)でさえ、浮動小数点コプロセッサはしばしば高価なアドオンでした。

浮動小数点演算をすべて行うには、かなり大きなライブラリが必要でした。そして、数学は遅くなるだろう。したがって、フロートを使用することはほとんどありません。整数またはスケーリングされた整数ですべてを実行しようとしました。math.hをインクルードする必要があるとき、歯を食いしばりました。多くの場合、それを回避するために独自の近似値とルックアップテーブルを作成します。

トレードオフは長い間存在していました。「fastmath」などと呼ばれる競合する数学パッケージが時々ありました。数学のための最良の解決策は何ですか?本当に正確だが遅いもの?不正確ですが高速ですか?トリガー関数の大きなテーブル?ほとんどの実装が明らかになるのは、コプロセッサーがコンピューター内にあることが保証されるまではありませんでした。組み込みのチップに取り組んでいて、数学の問題を処理するために数学ライブラリを組み込むかどうかを決定しようとしているプログラマーがいると思います。

それが数学が標準ではなかった理由です。多くの、またはおそらくほとんどのプログラムは、単一のフロートを使用しませんでした。FPUが常に使用されていて、浮動小数点数と倍精度浮動小数点数が常に操作するのに安価だったとしたら、「stdmath」があったことは間違いありません。


Heh、私はデスクトップPCでJavaの(1 + x)^ yにパデ近似を使用しています。Log、exp、powはまだ遅い。
quant_dev 2009年

いい視点ね。そして、オーディオプラグインでsin()の近似を見てきました。
Nosredna 09年

11
これlibmがデフォルトでリンクされていない理由を説明していますが、数学はC89の標準であり、それ以前はK&Rが事実上標準化していたため、「stdmath」の発言は意味がありません。
Fred Foo

@FredFooタイプとインターフェースは標準化されましたが、実装は標準化されていませんでした。Nosrednaは標準の数学ライブラリを参照していると思います。
Tim Bird

72

誰も修正しようとしないとんでもない歴史的慣習のために。CとPOSIXに必要なすべての機能を単一のライブラリファイルに統合すると、この質問が何度も繰り返されるのを回避できるだけでなく、.soリンクされた各ファイルにファイルシステム操作が必要になるため、動的リンク時に時間とメモリを大幅に節約できます。それを見つけて見つけるために、そして静的変数、再配置などのためのいくつかのページ

すべての機能が1つのライブラリとしているの実装-lm-lpthread-lrt、などのオプションは一切-OPS(または空へリンクされていない.aファイル)が完全にされるPOSIXの準拠と確かに望ましいです。

注:C自体はコンパイラーの呼び出し方法について何も指定していないため、POSIXについて話しています。したがってgcc -std=c99 -lm、準拠動作のためにコンパイラーを呼び出す必要がある実装固有の方法として扱うことができます。


9
+1は、POSIXではlibm、libc、およびlibrtライブラリーが分離して存在する必要がないことを示しています。例として、Mac OSではすべてが単一のlibSystem(libdbm、libdl、libgcc_s、libinfo、libm、libpoll、libprocおよびlibrpcsvcも含む)にあります。
F'x

3
–1は、リンクまたは数値でバックアップすることなく、パフォーマンスへのライブラリルックアップの影響を推測します。「プロフィール。推測しないでください」
F'x

12
これは推測ではありません。発表した論文はありませんが、すべての測定を自分で行ったので、その差は非常に大きくなっています。straceいずれかのタイミングオプションを使用して、動的リンクに費やされた起動時間を監視するか./configure、すべての標準ユーティリティが静的リンクされているシステムと動的リンクされているシステムでの実行を比較します。主流のデスクトップアプリ開発者やシステムインテグレーターでさえ、動的リンクのコストを認識しています。これが、プレリンクのようなものが存在する理由です。これらの論文のいくつかでベンチマークを見つけることができると思います。
R .. GitHub ICE HELPING ICEの停止2011年

1
POSIX -lm受け入れられる必要あり、数学インターフェイスを使用するアプリケーションはを使用する必要があります-lmが、実際のライブラリファイルではなく、コンパイラコマンドによって処理される(または無視される)内部オプションの場合もあります。または.a、インターフェースがメインlibcにある場合は、空のファイルにすることもできます。
R .. GitHub ICE HELPING ICEを停止する2011年

6
@FX:前にこれを言及するのを忘れた理由がわからない:strace -tt動的リンクに費やされた時間を簡単に表示します。きれいじゃない。Linuxでは、検査/proc/sys/smapsすると追加のライブラリのメモリオーバーヘッドが表示されます。
R .. GitHub ICE HELPING ICEを停止

33

のでtime()、いくつかの他の機能がされているbuiltin(Cライブラリで定義libc自体)とGCCは常に libcにリンクしていない限り、使用する-ffreestandingコンパイルオプションを。ただしlibm、gccによって暗黙的にリンクされていない数学関数が存在します。


8
LLVM gccでは、-lmを追加する必要はありません。どうしてこれなの?
bot47

26

説明はここにあります

したがって、プログラムが数学関数を使用してを含むmath.h場合は、-lmフラグを渡して数学ライブラリを明示的にリンクする必要があります。この特定の分離の理由は、数学者が数学の計算方法に非常にうるさく、標準の実装ではなく独自の数学関数の実装を使用したい場合があるためです。数学関数がlibc.aそれにまとめられていた場合、それを行うことはできません。

[編集]

しかし、私がこれに同意するかどうかはわかりません。たとえば、を提供するライブラリーがあり、sqrt()それを標準ライブラリーの前に渡すと、Unixリンカーがバージョンを取得しますよね?


10
それが起こるという保証はないと思います。代わりに、シンボルの競合が発生する可能性があります。それはおそらくリンカとライブラリのレイアウトに依存するでしょう。私はまだその理由が弱いと思います。カスタムsqrt関数を作成している場合、たとえ同じことを行っていても、標準のsqrt関数と同じ名前を付けてはいけません...
ephemient

1
実際、名前の付いた独自の関数(非静的)を作成するsqrtと、動作が定義されていないプログラムになります。
R .. GitHub ICE HELPING ICEの停止

@Bastien良い発見。では、「標準ライブラリの前」とはどういう意味ですか?標準ライブラリはデフォルトでリンクされており、コマンドラインオプションを介してリンクする必要はないと思いました。したがって、標準ライブラリはリンカにとって最初の頼りになるものであり、「標準ライブラリの前」に独自の実装を配置することはできません。
Rocky Inde

@RockyInde:私の答えを見てください、私は実際には「標準の数学ライブラリの前」を意味していたと思います。しかし、標準Cライブラリをリンクしないコンパイラオプションがあると思います。
BastienLéonard15年

@BastienLéonard私はバージョン7.2のgccを使用していますが、これ-lmは完全にオプションです。アイデア
東華劉

5

外部ライブラリへのリンクについては、GCCの概要-外部ライブラリとのリンクで詳しく説明しています。ライブラリが標準ライブラリ(stdioなど)のメンバーである場合、それらをリンクするためにコンパイラ(実際にはリンカ)に指定する必要はありません。

編集:他のいくつかの回答とコメントを読んだ後、両方にリンクしているlibc.aリファレンスとlibmリファレンスには、なぜ2つが分離しているのかについて多くの説明があると思います。

「libm.a」(数学ライブラリ)の関数の多くは「math.h」で定義されていますが、libc.aにはありません。混乱を招く可能性のあるものもありますが、経験則としては、CライブラリにはANSIが規定する必要のある関数が含まれているため、ANSI関数のみを使用する場合は-lmは必要ありません。対照的に、 `libm.a 'はより多くの関数を含み、matherrコールバックやFPエラーの場合の動作のいくつかの代替標準への準拠などの追加機能をサポートします。詳細は、セクションlibmを参照してください。


1
これは、なぜマッチライブラリを個別にリンクする必要があるのか​​という質問には答えません。明らかに、OpenGLライブラリを個別にリンクする必要がありますが、おそらく数学ライブラリが一般的に便利です。
David Thornley、

@David:そうだね。これがOPが尋ねていたビットであるかという質問から、私にははっきりしませんでした。あなたがコメントしたように私は私の答えを編集していました。
リザードに請求する'06年

sqrt関数を使用するプログラムをコンパイルした理由を知っていますが、を介してライブラリを含めなくても機能し-lmます。ありがとう!
L_K 2017年

5

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に注意してください。


3

それは一種の恣意的だと​​思います。どこかに線を引く必要があります(どのライブラリがデフォルトで、どのライブラリを指定する必要があるか)。

同じ機能を持つ別のものと交換する機会が与えられますが、そうすることはあまり一般的ではないと思います。

編集:(私のコメントから):gccは、元のccとの下位互換性を維持するためにこれを行うと思います。なぜccがこれを行うのかについての私の推測は、ビルド時間のためです-ccは、現在よりもはるかに少ない電力のマシン用に作成されました。多くのプログラムには浮動小数点演算機能がなく、おそらく一般的に使用されていないすべてのライブラリをデフォルトから除外しました。UNIX OSのビルド時間とそれに伴うツールが原動力だったと思います。


私は質問の背後にある考え方は、libmの内容が主に標準Cライブラリの一部であるということだと思いますが、なぜそれらはlibcにないのですか?
エヴァンテラン

1
gccの理由は、AT&T Unixの元のccとの互換性を維持するためです。私は1988年に3B2を使用しましたが、数学を得るために-lmを使用する必要がありました。当時はそれは完全に恣意的でした。Visual Studioでは、数学を追加する必要があったことを覚えていませんが、Cランタイムライブラリのように見えることがあります。コンパイラベンダーには理由があると思いますが(ビルド時間?)、今のところ、gccは下位互換性を維持しようとしているに違いありません。
ルーフランコ

3

stdlib.hまたはstdio.hを配置した場合、それらをリンクする必要はありませんが、コンパイル時にリンクする必要があります。

stdlib.hstdio.hヘッダファイルがあります。あなたはあなたの便宜のためにそれらを含めます。適切なライブラリにリンクした場合にのみ、どのシンボルが利用可能になるかを予測します。実装はライブラリファイルにあります。これは、関数が実際に存在する場所です。

含めることmath.hは、すべての数学関数にアクセスするための最初のステップにすぎません。

また、コンパイラーがシンボルについて情報を提供するだけの手順であるlibm場合でも、その関数を使用しない場合は、リンクする必要はありません#include <math.h>

stdlib.h、でstdio.h使用可能な関数を参照してくださいlibc。これはたまたまユーザーが自分で行う必要がないように常にリンクされています。


2

stdioは、デフォルトでgccがリンクする標準Cライブラリの一部です。

数学関数の実装は、デフォルトではリンクされない別個のlibmファイルにあるため、-lmを指定する必要があります。ちなみに、これらのヘッダーファイルとライブラリファイルとの間には何の関係もありません。


3
彼はそれを知っている..彼は理由
エヴァン・テラン

彼は理由を言います。Simonは、stdioなどの一部のライブラリはデフォルトでリンクされているが、数学ライブラリはデフォルトでリンクされていないため、指定する必要があると説明しています。
mnuzzo 2009年

5
質問の本質は、libmがデフォルトでリンクされていない(またはlibcから分離されている)理由が問われていることです。
エヴァンテラン

2

それをまったく使用しないアプリのパフォーマンスを少し向上させる方法だと思います。これは私の考えです。

x86 OS(および私は他の人も想像します)は、FPU状態をコンテキストスイッチに格納する必要があります。ただし、ほとんどのOSは、アプリが初めてFPUを使用しようとした後にのみ、この状態を保存/復元する必要があります。

これに加えて、ライブラリが読み込まれたときにFPUを正常な基本状態に設定する数学ライブラリにいくつかの基本的なコードが含まれている可能性があります。

そのため、数学コードをまったくリンクしない場合、これは発生しません。したがって、OSはFPU状態をまったく保存/復元する必要がないため、コンテキストスイッチがわずかに効率的になります。

ただ推測です。

編集:一部のコメントに応じて、同じ基本前提がFPU以外のケースにも適用されます(前提は、libmを使用しないアプリのパフォーマンスを少し向上させることでした)。

たとえば、Cの初期の段階でlikleyだったソフトFPUがある場合。libmを個別に設定すると、多くの大きな(使用されている場合は遅い)コードが不必要にリンクされるのを防ぐことができます。

さらに、使用可能な静的リンクのみがある場合、実行可能ファイルのサイズとコンパイル時間を短縮するという同様の議論が適用されます。


libmとリンクせずに、他の方法(たとえば、フロートでの操作)でx87 FPUに触れる場合、x86カーネルはFPU状態を保存する必要があります。これはあまり良い推測ではないと思います...
ephemient

もちろん、FPUを手動で使用する場合でも、カーネルはその状態を保存/復元する必要があります。(libmを使用しないことを含めて)決して使用しない場合は、使用する必要がないと言っていました。
エヴァンテラン

実際、カーネルに大きく依存する可能性があります。カーネルが使用する数学ライブラリには、それをオンにするsave_FPU_on_switch()関数を含めることができます。
Earlz 2009年

1
私の記憶が正しければ、問題全体が、マイクロプロセッサ上にある場合でも、浮動小数点コプロセッサよりもずっと前から存在しています。
Nosredna

@earlz:数学ライブラリのリクエストを保存するアプローチは、ひどい設計です。他の方法でFPUを使用している場合はどうなりますか?唯一の健全なアプローチ(常に保存/復元を除く)は、使用状況を検出してから保存/復元を開始することです。
エヴァンテラン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.