46

.cヘッダーファイルには、を「呼び出す」ファイルで使用されるさまざまな関数、構造体などの前方宣言があることを知っています#includeよね?私が理解している限り、「権力の分離」は次のように発生します。

ヘッダー ファイル:func.h

  • 関数の前方宣言を含む

    int func(int i);
    

C ソース ファイル:func.c

  • 実際の関数定義が含まれています

    #include "func.h"
    
    int func(int i) {
        return ++i ;
    }
    

C ソース ファイルsource.c(「実際の」プログラム):

#include <stdio.h>
#include "func.h"

int main(void) {
    int res = func(3);
    printf("%i", res);
}

私の質問は次のとおりです。これは、ファイル内#includeの内容をコピーする単なるコンパイラ ディレクティブであることを確認した場合、ファイルは実際に関数を実行する方法をどのように知っているのでしょうか。取得しているのはだけなので、実際にどのように機能を実行できるのでしょうか? の実際の定義にアクセスするにはどうすればよいでしょうか? ヘッダーには、「それが私の定義です。そこにある!」というような「ポインター」が含まれていますか?.h#include.cint func(int i);func

それはどのように機能しますか?

4

5 に答える 5

18

そのすべてを処理するのはリンカーです。funcコンパイラは、リンカーに対して「この外部シンボルがあります。解決してください」という特別なシーケンスをオブジェクト ファイルに出力するだけです。次に、リンカーはそれを確認し、他のすべてのオブジェクト ファイルとライブラリでシンボルを検索します。

于 2013-08-31T12:35:32.273 に答える
5

同じコンパイル単位内で定義されていないシンボルの宣言は、そのシンボルのアドレスのプレースホルダーを使用してオブジェクト ファイルにコンパイルするようコンパイラーに指示します。

リンカーは、シンボルの定義が必要であることを認識し、ライブラリやその他のオブジェクト ファイルでシンボルの外部定義を探します。

リンカが定義を見つけると、元のオブジェクト ファイルのプレースホルダは、最終的な実行可能ファイルで見つかったアドレスに置き換えられます。

于 2013-08-31T12:41:27.797 に答える
2

通常、次のようなファイルをコンパイルすると:

gcc -o program program.c

実際には、次の処理を行うドライバー プログラムを呼び出しています。

  • を使用した前処理(別のステップにするように要求した場合)cpp
  • コンパイル(前処理と統合される場合があります)を使用してcc1
  • as(ガス、GNU アセンブラー)を使用して組み立てます。
  • (GNU リンカ)collect2も使用するを使用してリンクします。ld

通常、最初の 3 つの段階では、単純なオブジェクト ファイル (.o拡張子) を作成します。これは、コンパイル ユニット (プリプロセッサによって #include およびその他のディレクティブが置き換えられた .c ファイル) をコンパイルすることによって作成されます。

第 4 段階は、最終的な実行可能ファイルを作成する段階です。ユニットのコンパイル後、コンパイラはいくつかのコードを参照としてマークし、リンカーによって解決する必要があります。リンカーの仕事は、多くのコンパイル ユニットを検索し、外部コンパイル ユニットへの参照を解決することです。

于 2013-08-31T13:14:13.800 に答える
2

ヘッダーは.c、同じプログラム内の他のファイルへのアクセスを提供するだけでなく、バ​​イナリ形式で配布されるライブラリへのアクセスも同様に提供します。あるファイルと別のファイルの関係は.c、別のファイルに依存するライブラリとまったく同じです。

実装の形式に関係なく、プログラミング インターフェイスはテキスト形式である必要があるため、ヘッダー ファイルは問題の分離として意味があります。

他の方もおっしゃっていますが、ライブラリとソース(翻訳単位)との間の関数呼び出しやアクセスを解決するプログラムをリンカと呼びます。

リンカーはヘッダーでは機能しません。すべての翻訳単位とライブラリで定義されているすべての名前の大きなテーブルを作成し、それらの名前をそれらにアクセスするコード行にリンクするだけです。C の古い使用法では、実装宣言なしで関数を呼び出すことさえできます。すべての未定義の型はint.

于 2013-08-31T12:39:20.050 に答える