13

extern をローカルで宣言し、変数を登録できるかどうか疑問に思っていました。それが可能である場合、課される制限は何でしょうか?

4

5 に答える 5

13

場合によっては、ローカル変数を extern として宣言できます

C99 N1256 標準案を読んでみましょう。

標準では、「ブロックスコープ」を持つものとして「ローカル変数」を呼び出します。

6.7.1/5「ストレージクラス指定子」には次のように書かれています:

ブロック スコープを持つ関数の識別子の宣言には、extern 以外の明示的なストレージ クラス指定子があってはなりません。

次に、ローカル変数に追加することの意味についてextern、6.2.2/4「識別子のリンク」は次のように述べています。

その識別子の前の宣言が可視であるスコープ内でストレージ クラス指定子 extern を使用して宣言された識別子の場合、前の宣言が内部リンケージまたは外部リンケージを指定している場合、後の宣言での識別子のリンケージはリンケージと同じです。事前の宣言で指定されています。前の宣言が表示されない場合、または前の宣言でリンケージが指定されていない場合、識別子には外部リンケージがあります。

それらのケースを分解しましょう。

事前申告なし

void f() {
    extern int i;
}

以下と同じです:

extern int i;
void f() {}

ただし、宣言は 内でのみ表示されfます。

これはi、以前の宣言が表示されていないためです。外部リンケージi(グローバル変数と同じリンケージ) も同様です。

前の宣言はリンケージを指定しない

int i;
void f() {
    extern int i;
}

以下と同じです:

void f() {
    extern int i;
}

int iパラグラフ6が次のように述べているため、前の宣言はリンケージを指定していないためです。

次の識別子にはリンケージがありません。オブジェクトまたは関数以外のものとして宣言された識別子。関数パラメーターとして宣言された識別子。ストレージ クラス指定子 extern なしで宣言されたオブジェクトのブロック スコープ識別子。

事前宣言は、内部または外部リンケージを指定します

extern int i;
void f() {
    extern int i;
}

以下と同じです:

extern int i;
void f() {}

と:

static int i;
void f() {
    extern int i;
}

以下と同じです:

static int i;
void f() {}

どちらの場合も、以前に表示されている外部および内部 ( static) リンケージ宣言がそれぞれあるためです。

ローカル外部を初期化する

無効な C:

void f() {
    extern int i = 0;
}

ブロック スコープ宣言には初期化があるためです。

有効な C:

extern int i = 0;
void f() {}

しかし、より短いものと同等であるため、間違いなく悪いスタイルです:

int i = 0;
void f() {}

6.7.8初期化が言うので:

識別子の宣言にブロックスコープがあり、識別子に外部または内部リンケージがある場合、宣言には識別子の初期化子がありません。

于 2015-06-19T07:52:32.010 に答える
9
  1. ローカル変数を extern として宣言できますか?

いいえ。ただし、グローバル変数はexternローカルで宣言できます。

// file1.c
int Count;

// file2.c
void foo(void) {
  extern int Count;
  Count++;
}
  1. レジスタ変数を extern として宣言できますか?

いいえ。変数は と ではない場合がexternありregisterます。

C11 dr 6.7.1 ストレージ クラス指定子
1ストレージ クラス指定子:
typedef
extern
static
_Thread_local
auto
register
制約
2 最大で 1 つのストレージ クラス指定子を宣言の宣言指定子で指定でき_Thread_localますstaticextern

于 2014-12-29T22:02:05.343 に答える
3

6.9 C99状態の外部定義:

ストレージクラス指定子autoおよびregisterは、外部宣言の宣言指定子に表示されないものとします。

于 2013-01-15T10:35:06.553 に答える
0

このフレーズregister variableは私には明確ではないので、OPが本当に興味を持っているものについて大胆な推測を1つ行い、元の質問をCould local variables be declared with extern specifier?次のスニペットに示すように言い換えます:

int main() {
    extern int x; // Is this OK?
    return 0;
}

答えはイエスです。

スコープ (可視性) とストレージは、2 つの独立した接続された概念です。ここでxは、1 つのローカル変数 (スコープ) があり、このブロック内でのみ表示されます。externつまり、これは単なる 1 つの宣言であり、この変数は別の場所で定義されています。明確な参照のためにC標準をお勧めします。

省略されたregister部分については、OPregisterregister int x. register次に、とexternを同時に指定することは違法です。

int main() {
    extern auto int x; // This is wrong.
    return 0;
}

At most, one storage-class specifier may be given in the declaration specifiers in a declaration, except that _Thread_local may appear with static or extern.

auto対称的な質問は次のとおりです。グローバル変数または外部変数を指定することは有効ですregisterか、これはまさにAlexey Frunzeの答えです。

auto int x; // This is wrong.
int main() {
    return 0;
}
于 2014-12-29T21:20:02.880 に答える
0

グローバル変数は としてのみ定義できますextern。他の場所で定義されていることをコンパイラ (およびリンカー) に伝えます。

ローカル変数は、スタックまたはレジスタで作成されるため、ローカル スコープにのみ存在します。実行が (もはや) スコープ内にない場合、スタックはアンロールされます (したがって、空き領域が再び利用可能になります) か、レジスタは他の目的に使用され、変数は (もはや) 存在しません。

そのため、ローカル extern を定義することは「奇妙」で不可能です (スタックの使用が原因で)。

于 2013-01-15T10:32:33.540 に答える