読んでいるときに次の問題に遭遇しました...この背後にあるロジックを理解できません。
auto int c;
static int c;
register int c;
extern int c;
最初の 3 つが定義で、最後の 1 つが宣言であるとします。
読んでいるときに次の問題に遭遇しました...この背後にあるロジックを理解できません。
auto int c;
static int c;
register int c;
extern int c;
最初の 3 つが定義で、最後の 1 つが宣言であるとします。
の最後のものは、 のextern
ストレージを定義していませんc
。がどこかに存在することを示すだけであり、リンカーはそれを別の場所で定義されたc
グローバルに解決できるはずです。c
単一の .c ファイルをコンパイルしてリンクし、最後のファイルを使用しようとするとc
、リンカー エラーが発生します。最初の 3秒では、現在のコンパイル単位に実体がある (定義されc
ている) ため、そうではありません。
extern
宣言と定義について詳しく知りたい場合は、このトピックに関する優れた記事をご覧ください。その記事から引用するには:
変数/関数の宣言は、変数/関数がプログラムのどこかに存在することを単に宣言しますが、メモリはそれらに割り当てられません
このキーワードextern
は、変数 (またはおそらく関数) の定義が別の場所にあるという事実を参照します。次にコンパイラは、この宣言を別のファイル内の定義済み本体にリンクします。前の 3 つのキーワードは宣言を示します。変数は他の場所で定義されていないため、定義されていませんprototypes
。
たとえば、次のようなプロジェクト構造があるとします。
..
-- main.c
-- client.c
-- client.h
-- server.c
-- server.h
ヘッダー ファイルを使用してこれらをコンパイルするgcc
と、ヘッダー ファイルは通常define
、プログラムに必要な変数になります。declaration
これにより、.c ファイル内のシンボルにリンクするシンボルが割り当てられます。これは、コンパイラがさまざまなプロジェクト ファイルを.o
オブジェクトとリンクする方法です。objdump -d
プログラムの実際の逆アセンブル構造をデバッグするために (Linux を使用していると仮定して) を使用すると、これらすべてがどのように表示されるかにさらに興味があるかもしれません。
楽しんで頑張ってください!
最初の 3 つのステートメントは、実際にint
.
最後のものはそうではありません。コンパイラに伝えるのは、別のコンパイル単位のどこかで、int
呼び出されc
た が定義されるということだけです。
定義されていない場合、後でリンカー エラーが発生します。当然のことながら、リンカはそれc
が定義されていないと言うでしょう。
最初の 3 つは、変数用のストレージを確保するための定義です。
最後の 1 つは のストレージを割り当てませんint c
。他の場所で割り当てられ、名前が付けられたストレージを使用するだけです。