10

静的外部変数とその使用法について知るために、小さな例を試しています。静的変数はローカル スコープであり、外部変数はグローバル スコープです。

static5.c

#include<stdio.h>
#include "static5.h"
static int m = 25;
int main(){
 func(10);
 return 0;
}

static5.h

#include<stdio.h>
int func(val){
 extern int m;
 m = m + val;
 printf("\n value is : %d \n",m);
}

gcc static5.c static5.h

o/p :

static5.c:3: error: static declaration of m follows non-static declaration
static5.h:3: note: previous declaration of m was here

編集済み

正しいプログラム:

a.c:
#include<stdio.h>
#include "a1_1.h"
int main(){
 func(20);
 return 0;
}

a1.h:
static int i = 20;

a1_1.h:
#include "a1.h"
int func(val){
 extern int i;
 i = i + val;
 printf("\n i : %d \n",i);
}

これは問題なく動作します。ただし、これは単一のコンパイル単位にコンパイルされます。したがって、静的変数にアクセスできます。コンパイル単位全体で、extern 変数を使用して static 変数を使用することはできません。

4

4 に答える 4

20

staticには非常に単純なロジックがあります。変数が の場合はstatic、それがグローバル変数であることを意味しますが、スコープは定義された場所に限定されます (つまり、そこでのみ表示されます)。例えば:

  • 関数の外側: グローバル変数ですが、ファイル内でのみ表示されます (実際には、コンパイル ユニット)
  • 関数内: グローバル変数ですが、関数内でのみ表示されます
  • (C++) クラス内: グローバル変数ですが、クラスにのみ表示されます

static次に、C11標準がandに関して何を述べているかを見てみましょうextern(強調は私のものです):

6.2.2.3

オブジェクトまたは関数のファイル スコープ識別子の宣言にストレージ クラス指定子が含まれているstatic場合、識別子には内部リンケージがあります。

6.2.2.4

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

6.2.2.7

翻訳単位内で、同じ識別子が内部リンケージと外部リンケージの両方で表示される場合、動作は未定義です。

したがって、標準では、次の場合は最初に次のように述べています。

static int m;
extern int m;

次に、2 番目の宣言 ( with extern) は最初の宣言を考慮し、最終的にmstatic.

ただし、それ以外の場合で、内部リンケージと外部リンケージの両方を持つ宣言がある場合、動作は未定義です。これにより、実際には 1 つのオプションしか残されません。

extern int m;
static int m;

つまり、extern宣言前のstatic宣言です。gcc は、この未定義の動作の場合にエラーを発生させるのに十分な機能を備えていました。

于 2013-06-11T12:06:13.847 に答える
17

これを覚えておいてください(Eli Benderskyを引用):

  • 関数内の静的変数は、呼び出し間でその値を保持します。
  • 静的グローバル変数または関数は、宣言されているファイルでのみ「表示」されます

コード内でstatic int m = 25;は、mスコープがそのファイルのみに限定されていることを意味します。つまり、内部でのみ表示され、それ以外の場所には表示されstatic5.cません。

moutside ofを使用したい場合は、変数の宣言からstatic5.cキーワードを削除してください。static

より標準的な説明と例については、Eli Bendersky によるこの回答を参照してください。

編集: (Klas の推奨に従って) **実際のスコープはコンパイル単位であり、ソース ファイルではありません。コンパイル単位は、プリプロセッサ ステップの後にファイルがどのように見えるかです。

于 2013-06-11T10:11:33.903 に答える
3

問題は、エラー メッセージに記載されているとおりです。mは法線として宣言されていますintが、後で として定義されていstatic intます。

extern変数のグローバルテーブルで変数を探すようにコンパイラ/リンカーに指示します。

static(関数外) は、変数のグローバル テーブルから変数を除外するようにコンパイラに指示します。

対立が見えますか?

この問題を解決するには、定義からキーワードを削除するかstatic、定義をstatic5.h.

ファイルを設計した方法は、ベスト プラクティスとは見なされないことに注意してください。通常、インクルード ファイルには関数が含まれていません。

于 2013-06-11T10:43:28.783 に答える
2

m を宣言するときにキーワード static を削除すると、エラーが削除され、50 として回答を得ることができます。static キーワードは、スコープをファイル内で制限するようにします。

于 2013-06-11T10:19:05.587 に答える