web-dev-qa-db-ja.com

なぜ静的変数に外部リンクしないのですか?

Nが(別のファイルで)_extern int n_と宣言されたときに_static int n_がコンパイルされないのに、_int n_が宣言されたときに機能するのはなぜですか? (これらの宣言は両方ともファイルスコープにありました。)

基本的に、ファイルスコープの_int n_が同じスコープの_static int n_と同じではないのはなぜですか? externとの関係でのみですか?もしそうなら、私はexternについて何が欠けていますか?

54
Jared Pochtar

staticの全体的および全体的な目的は、変数が変数が宣言されているソースファイルに対してプライベートであることを宣言することです。したがって、外部からの接続を防止するという正確な役割を果たしています。

ファイルスコープ変数の定義には4つの種類があることに注意してください。

  1. int blah = 0; —何とかはこのファイルで定義され、他のファイルからアクセスできます。他のファイルの定義は重複しているため、エラーが発生します。
  2. extern int blah; — blahは他の場所で定義する必要があり、このファイルから参照されます。
  3. int blah; —これは、FORTRAN COMMONと同等の道徳的なものです。これらはいくつでもファイルに入れることができ、それらはすべてリンカによって1つの共有intに解決されます。 (*)
  4. static int blah;(オプションで初期化子を使用)—これは静的です。このファイルには完全にプライベートです。他のファイルの外部からは見えません。すべてがstatic TYPE blah;を宣言する多くの異なるファイルを持つことができ、それらはすべてdifferentです。

オーディエンスの純粋主義者向け: 'file' =compilation unit

静的内部関数(ファイルスコープではない)はさらに厳密にスコープされていることに注意してください。2つの関数が同じファイル内でstatic int bleh = 0;を宣言する場合、それらは無関係です。

(*):よく知らない人のために:通常のパターンでは、1つのコンパイル単位でグローバル変数を定義する必要があり、他のコンパイル単位はそれを参照できます。それはそのコンパイル単位で「生きています」。上記のケース(3)では、ファイル(またはすべてのファイル)がそれを定義していません。 2つのファイルがint blah = 0;と言う場合、リンカーは複数の定義について不平を言います。 2つのファイルがint blah;と言う場合、リンカは単一のグローバルintを元気に作成し、すべてのコードがそれを参照するようにします。

114
bmargulies

標準Cには、関数の外部で宣言された変数のスコープが2つあります。 static変数は、それを宣言したコンパイル単位(つまり、ファイル)内でのみ表示され、非静的変数はプログラム全体で表示されます。 extern宣言は、変数の場所はまだ知られていないが、リンカーによってソートされることを示しています。非静的変数と互換性がありますが、extern staticはおかしな話です!

もちろん、実際には最近では他の可視性もあります。特に、単一のソースファイルとプログラム全体のレベルの間にスコープレベルがあります。単一の共有ライブラリのレベルは有用です(GCC関数属性などのメカニズムで設定可能)。しかし、それは非静的変数のテーマの単なるバリエーションです。 staticは、以前と同じ解釈を保持します。

6
Donal Fellows

MSDNドキュメントによると:

変数を変更する場合、staticキーワードは、変数に静的期間(プログラムの開始時に割り当てられ、プログラムの終了時に割り当て解除される)があることを指定し、別の値が指定されない限り0に初期化します。 ファイルスコープで変数または関数を変更する場合、staticキーワードは、変数または関数に内部リンケージがあることを指定します(その名前は、宣言されているファイルの外部からは見えません)。

http://msdn.Microsoft.com/en-us/library/s1sb61xd(v = vs.80).aspx :2013年6月

1
felknight

iv.c:2:1:エラー:宣言指定子の複数のストレージクラスextern static int i; ^

それが、静的変数を外部化しようとすることです。 extern static int iを宣言します。 -宣言float int iに類似しています。同じ宣言にfloatとintを含めることはできませんか?同様に、同じ宣言にexternとstaticを含めることはできません。

1
Gautham