2013-06-11 16 views
7

静的な外部変数とその使用方法を知る小さな例を試しています。静的変数はローカルスコープで、外部変数はグローバルスコープです。mの静的宣言は非静的宣言に従います

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 

EDITED

正しいプログラム:

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); 
} 

これは罰金完全に正常に動作します。しかし、これは1つのコンパイル単位にコンパイルされます。したがって、静的変数にアクセスすることができました。コンパイル単位全体では、extern変数を使用して静的変数を使用することはできません。

+0

「extern int m;」は関数本体の外にあるべきではありませんか? – Kninnug

+1

mはstatic5.cでstaticとして宣言されているため、スコープはfile.so内にあります。 –

+0

だから質問は何ですか? mはstatic5.cファイルには静的なので、他の場所にアクセスすることはできません。'extern 'で宣言することさえできません。 – greydet

答えて

13

は(イーライBenderskyを引用)、これを覚えて:

  • 関数内スタティック変数は 呼び出しの間にその値を保持します。
  • 静的グローバル変数や関数だけ にそれはあなたのコードで

で宣言されていますファイルを「見」され、static int m = 25;は、m範囲がそのファイルだけに限定されることを意味しつまり、それはstatic5.c内にしか見えず、他の場所には見えません。

static5.cの外に使用する場合は、変数の宣言からキーワードstaticを削除してください。 (KLAS'推奨に従って) **実際の範囲は、コンパイル・ユニットではなく、ソースファイルである:より正規説明について

は、例えばと共に、this answer by Eli Bendersky

EDITを参照します。メートルを宣言するとエラーが削除され、あなたが50として答えを得ることができるようになりますstaticキーワードはスコープを行いながらコンパイル単位は

+3

スコープはソースファイルではなく、コンパイル単位です。コンパイル単位は、ファイルがプリプロセッサステップの後に現れる方法です。そして、funcは同じファイルにあります。 –

+0

@KlasLindbäckコメントをいただきありがとうございます!私は私の答えを更新するつもりです。 – NlightNFotis

+0

@NlightNFortis:そのコンパイル単位は1つだけです。私はgcc static5.cとstatic5.hをします。コードは単一のコンパイル単位にコンパイルされます。しかし、まだ私はエラーを持っています。 – Angus

2

staticキーワードを削除したファイルは、プリプロセッサ工程の後に見える方法ですファイル内で制限する。

3

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

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

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

競合が表示されますか?

問題を解決するには、staticキーワードを定義から削除するか、または上記の定義をstatic5.hの上に移動します。

ファイルの設計方法は、ベストプラクティスとはみなされません。インクルードファイルには、通常、関数は含まれていません。

+0

私は最初もそうだと思っていましたが、標準はより柔軟です。 'static'宣言が' extern'宣言の前にある場合、それは完全に大丈夫です。参考まで私の答えを見てください。 'extern'宣言が最初に来る場合にのみ問題があります。 – Shahbaz

+0

@Shahbaz説明をありがとう。私はextern宣言が単に余計なものであると誤っているかどうかは分からなかった。 –

14

staticには非常に単純なロジックがあります。変数がstaticであれば、グローバル変数であることを意味しますが、スコープは定義されている場所(つまりそこにしか表示されていない)に限定されます。グローバル変数だけファイル(実際には、コンパイル単位)内の可視関数内

  • :内部グローバル変数が、可視のみ機能
  • (C++)以内例えば:関数外

    • クラス:

      :グローバル変数だけがクラスに表示

    今度は、C11規格はstaticextern(強調鉱山)に関する言うか見てみましょう210

    6.2.2.3

    オブジェクトまたは関数のファイルスコープ識別子の宣言が記憶クラス指定子staticが含まれている場合、識別子は、内部結合を有します。前宣言は、内部または外部リンケージを指定している場合、その識別子の前に宣言は、表示された範囲内のストレージ・クラス指定extern、リンケージで宣言された識別子について

    6.2.2.4

    後の宣言での識別子の前の宣言で指定されたリンケージと同じです。以前の宣言が表示されていない場合、または前の宣言でリンケージが指定されていない場合、識別子には外部リンケージがあります。

    6.2.2.7

    、翻訳単位内に、同一の識別子は、内部と外部の両方のリンクが表示されている場合、動作は未定義です。

    ので、標準では、あなたが持っている場合、最初の、と言っている:

    static int m; 
    extern int m; 
    

    を、その後(extern付き)2番目の宣言は、最初のものを考えてしまうと、最後にmはまだstaticだろう。

    しかし、それ以外の場合は、内部と外部の両方のリンケージで宣言がある場合、その動作は未定義です。 static宣言の前に

    extern int m; 
    static int m; 
    

    すなわち、extern宣言:これは、実際に一つだけのオプションを私たちに残します。 gccは、の定義されていない動作のエラーを表示するのに十分な大きさでした。

  • +0

    こんにちは、すてきな説明に感謝します。しかし、静的と外部を一緒に使うことは私にはうんざりされています。これは私にはvar "a"を静的に関連付けるだけで、他のすべてのファイルにはエクスポーズする " 。矛盾するように聞こえる。私の理解で正しいですか?もしそうでなければ、いつ 'static'と' extern'を一緒に使う必要がありますか?前もって感謝します。 – Unheilig

    +0

    @unheilig、あなたの個人的なプロジェクトでは真実ですが、一般的にメリットがないわけではありません。 'extern 'の前の' static'の場合、extern関数宣言を持つ通常のヘッダファイルを持つライブラリを想像してください。ヘッダをインクルードする前に 'static'と宣言することで、これらの関数のいくつかをオーバーライドすることができます。このメソッドでは、例えばある種のコンパイル時に有効な 'valgrind 'が可能です。 – Shahbaz

    +0

    もう1つの方法はおそらく問題になります。なぜなら、 'extern'宣言の後、コンパイラはその宣言にリンクするコードを生成するでしょうが、後で' static'であると言われていたので、コンパイラは前のコード。 Cコンパイラはシングルパスなので、せいぜい迷惑です。 – Shahbaz

    関連する問題