外部レベル宣言のストレージ クラス指定子
外部変数はファイル スコープの変数です。 これらは、関数の外部で定義され、多くの関数に使用できる可能性があります。 関数は外部レベルでのみ定義できるため、入れ子にできません。 既定では、同じ名前の外部変数と関数へのすべての参照は、同じオブジェクトへの参照であり、"外部リンケージ" が含まれていることを意味します。 ( static
キーワードを使用して、この動作をオーバーライドできます。)
外部レベルの変数宣言は、変数の定義 ("宣言の定義")、または別の場所で定義された変数の参照 ("宣言の参照") です。
変数も初期化する (暗黙的または明示的に) 外部変数宣言は、変数の定義宣言です。 外部レベルの定義は複数の形式にすることができます。
static
のストレージ クラス指定子で宣言する変数。 「初期化」で説明されているように、定数式を使ってstatic
変数を明示的に初期化できます。 初期化子を省略すると、変数は既定で 0 に初期化されます。 たとえば、次の 2 つのステートメントはどちらも変数k
の定義と見なされます。static int k = 16; static int k;
外部レベルで明示的に初期化する変数。 たとえば、
int j = 3;
は変数j
の定義です。
外部レベル (つまり、全関数の外側) の変数宣言では、 static
または extern
ストレージ クラス指定子を使用するか、ストレージ クラス指定子を完全に省略できます。 auto
および register
storage-class-specifier
ターミナルを外部レベルで使用することはできません。
外部レベルで変数を定義すると、その変数は翻訳単位の残りの部分全体にわたって参照できます。 変数は、同じソース ファイルでの宣言に先立って表示されません。 また、以下で説明するように、参照宣言が表示されるようにしない限り、プログラムの他のソース ファイルに表示されません。
static
に関する規則には以下が含まれます。
static
キーワードなしですべてのブロックの外側で宣言された変数は、プログラム全体を通して常に値を保持します。 特定の翻訳単位へのアクセスを制限するには、static
キーワードを使用する必要があります。 これによって、"内部リンケージ" が設定されます。 プログラム全体でグローバルにするには、明示的なストレージ クラスを省略するか、キーワードextern
を使用します (次の一覧の規則を参照してください)。 これによって、"外部リンケージ" が設定されます。 内部リンケージおよび外部リンケージは「Linkage (リンケージ)」でも説明します。プログラム内で 1 回だけ、外部レベルで変数を定義できます。 同じ名前と、別の翻訳単位の
static
ストレージ クラスの指定子を持つ別の変数を定義できます。 各static
定義はその独自の翻訳単位内でのみ参照できるため、競合は発生しません。 これによって、1 つの翻訳単位内の関数間で共有され、他の翻訳単位からは参照されない識別子名を、簡単に隠すことができます。static
ストレージ クラス指定子は、関数にも適用できます。 関数static
を宣言する場合、その名前は宣言されているファイルの外部からは参照できません。
extern
を使用するための規則は次のとおりです。
extern
ストレージ クラス指定子は、他の場所で定義された変数への参照を宣言します。extern
宣言を使用して、別のソース ファイル内の定義を参照できるようにするか、同じソース ファイルで変数の定義前にその変数を参照できるようにすることが可能です。 外部レベルで変数への参照を宣言すると、その変数は、宣言した参照が発生する翻訳単位の残りの部分全体で参照できます。extern
参照を有効にするには、参照する変数は 1 回だけ外部レベルで定義する必要があります。 この定義 (extern
ストレージ クラスを含まない) は、プログラムを構成する任意の翻訳単位内で行うことができます。
例
次の例では外部宣言を示します。
/******************************************************************
SOURCE FILE ONE
*******************************************************************/
#include <stdio.h>
extern int i; // Reference to i, defined below
extern void other ( void ); // Reference to other(), defined in second source file
void next( void ); // Function prototype
int main()
{
i++;
printf_s( "%d\n", i ); // i equals 4
next();
}
int i = 3; // Definition of i
void next( void )
{
i++;
printf_s( "%d\n", i ); // i equals 5
other();
}
/******************************************************************
SOURCE FILE TWO
*******************************************************************/
#include <stdio.h>
extern int i; // Reference to i in
// first source file
void other( void )
{
i++;
printf_s( "%d\n", i ); // i equals 6
}
この例の 2 つのソース ファイルには、i
の 3 つの外部宣言の合計が含まれます。 1 つの宣言のみが "定義宣言" です。その宣言
int i = 3;
によって、グローバル変数 i
が定義され、初期値 3 で初期化されます。 extern
を使用している最初のソース ファイルの最上部にある i
の "参照" 宣言により、ファイルの定義宣言の前にグローバル変数を参照できるようになります。 また、2 番目のソース ファイルの i
の参照宣言は、そのソース ファイルで変数を表示します。 変数の定義インスタンスが翻訳単位で提供されていない場合、コンパイラは次があるものと見なします。
extern int x;
参照宣言と定義参照
int x = 0;
プログラムの別の翻訳単位に表示されます。
3 つの関数 main
、next
、および other
はすべて、同じタスクを実行します。これらは i
を増やし、それを出力します。 値 4、5、および 6 が出力されます。
変数 i
が初期化されていない場合は、自動的に 0 に設定されます。 この場合、値 1、2、および 3 が出力されています。 変数の初期化については、「初期化」をご覧ください。