• ベストアンサー

static と externについて

以下のようなプログラムを組んでいます。 //main.h static int hoge; void someOperation(); //hoge.cpp #include "main.h" extern int hoge; void someOperation() { hoge = 15; } //main.cpp #include <stdio.h> #include "main.h" extern int hoge; int main() { someOperation(); printf("%d\n",hoge); return 0; } このプログラムを実行したのですが、自分の予想した15という出力ではなく、不定値になるようなのです。 自分の予想では、someOperationで操作するhogeも、main内で操作するhogeも同じになるようにと思いexternをつけているのですが、なにがまずいのでしょうか? ご存知の方、ご教授お願いします。

  • qOat
  • お礼率80% (42/52)

質問者が選んだベストアンサー

  • ベストアンサー
回答No.1

結論から言えば、 static int hoge; で、static をつけてはいけません。 この場合、hoge.cpp と main.cpp のどちらか一方に、 int hoge; 他方に、 extern int hoge; が必要になります。 これを一括管理するテクニックとしては、以下のようなものが紹介されていました。 main.h #if defined(GLOBAL_HERE) #define EXT #define DEF(x) = (x) #else #define EXT extern #define DEF(x) #endif EXT int hoge; main.cpp #define GLOBAL_HERE // この後で、inlude すると、EXT 指定した変数は、実態が宣言される #include "main.h" hoge.cpp // こちらでは(ほかのファイルでも) GLOBAL_HERE は定義しない #include "main.h" // こちらでは、EXT 指定した変数は、 extern と読み替えられる 初期化が必要なときには、 EXT int hog DEF(10); などとすると、 #define GLOBAL_HERE のあとで include された場合は、 int hoge = (10); そうでない場合には、 extern int hoge; となります。

qOat
質問者

お礼

迅速な回答ありがとうございます。 確かにこの方法なら、一箇所に宣言をまとめられて気持ちがいいですね。 ありがとうございました。

その他の回答 (1)

  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.2

★まずいですね。 ・まず main.h のヘッダファイルに static int hoge という変数の実体があります。  結論から言うとこのような記述は避けるべきなのです。  理由は ・hoge.cpp で main.h をインクルードしていますが、ここで hoge.cpp でしか使えない  static int hoge が実体として作られます。これに 15 を代入していますが、static キーワードが  付いているので他のソースファイル(main.cpp)からアクセスできません。見えないので。 ・また main.cpp でも main.h をインクルードしていますが、こんどは main.cpp 用でしか使えない  static int hoge が実体として作られます。つまり2つの hoge 変数が存在します。 ・main.cpp では、この自分で見える hoge=0 が表示されます。  決して hoge.cpp の hoge 変数ではありません。注意。 // hoge.cpp static int hoge=15; ←main.cpp からは参照できない(隠されている) // main.cpp static int hoge=0; ←main.cpp ではこれを表示している ※hoge がそれぞれのソースファイルに1つずつ作られて合計2つあります。 解決策: ・main.h ヘッダには extern int hoge; のプロトタイプ宣言だけをします。  そして hoge.cpp に extern int hoge=0; と定義します。  そして someOperation() 関数内で hoge=15; とします。 ・main.cpp では main.h をインクルードしますので『extern int hoge;』の  記述は必要ありません。→あっても問題はありませんけど。 //main.h extern int hoge; void someOperation(); //hoge.cpp #include "main.h" extern int hoge = 0; ←※かならず何かの値を代入すること void someOperation() {  hoge = 15; } //main.cpp #include <stdio.h> #include "main.h" int main( void ) {  someOperation();  printf( "%d\n", hoge );  return 0; } 以上。

qOat
質問者

お礼

丁寧な回答ありがとうございます。 疑問が氷解しました。

関連するQ&A

  • extern記憶クラス指定子を使う事について

    prg1.cpp----------------------------- #include<stdio.h> void func(void); int gg=5678; int main(void) { printf("main gg=%d\n",gg); func(); return 0; } ---------------------------------- prg2.cpp-------------------------- #include<stdio.h> extern int gg; void func(void) { printf("func gg=%d\n",gg); } ---------------------------------- 以上「prg1.cpp」と「prg2.cpp」という名前のふたつのファイルを作成し、「prg1.cpp」で宣言したグローバル変数を「prg2.cpp」で利用可能にしたいと思っています。 それには、「prg1.cppをコンパイルし、prg2.cppもコンパイルして、両者のオブジェクト(コンパイル後のファイル)をリンクする」と参考書には書いてあったのですが、どのようにしたらリンクされるのかわかりません。 prg.1cpp---------------------- #include<stdio.h> void func(void); int gg=5678; int main(void) { printf("main gg=%d\n",gg); func(); return 0; } #include<stdio.h> extern int gg; void func(void) { printf("func gg=%d\n",gg); } ------------------------------- 以上のように、「prg1.cpp」のファイルに1つにまとめれば、なぜかよくわかりませんが実行できました。 しかし「prg1.cpp」と、「prg2.cpp」をリンクさせてみたいので、教えていただけると嬉しいです。

  • staticのスコープについて

    //main.c #include "myfunc.h" #include <stdio.h> static char hoge[10]; int main(void){ myfunc(hoge); printf("%c",*hoge); } ------------------ //myfunc.h void myfunc(char *hoge) { *hoge = 'a'; } 上記のようなプログラムの場合、 a と表示されると思いますが、この動作は保証されているのでしょうか? つまり、staticにて宣言したモジュール内の変数は、他モジュールにポインタを渡しても、内容は保証されるのかどうかと言う事なのですが。 よろしければ教えてください。

  • C言語で、記憶クラス指定子extern・staticを関数に指定

    C言語の本に、「関数の定義と呼び出す側が別ソースファイルの場合、プロトタイプはヘッダーファイルに書き、定義側と呼び出し側の両方でインクルードしましょう」ということが書かれていました。 例えば、 ===code1a.c=== extern void funcB(int); static void funcA() { funcB(1); } ===code1b.c=== void funcB(int a) { printf("%d\n",a); } このような場合には、もしcode1b.cの中の関数funcBに引数を追加した場合、再コンパイルしても気づかないのでよくない。 そこで、次のようにヘッダーファイルを作り、プロトタイプはそこに書くべきだ。 ***code2b.h*** extern void funcB(int); ***code2a.c*** #include "code2b.h" static void funcA() { funcB(1); } ******code2b.c**** #include "code2b.h" void funcB(int a) { printf("%d\n",a); } 記述は以上のようなことです。 #include "code2b.h" とは、 extern void funcB(int); が書いてあるのと同じだと思います。 私が思ったのは、本の勧める方法では、 funcBを定義しているcode2b.cで、プロトタイプの記憶クラス指定子が、externになっているが良いのか(externとは、別のソースファイルで定義されているという意味ではないか)ということです。 extern, staticは、プロトタイプに書くべきなのか、関数の定義に書くべきなのか、も両方に書くべきなのでしょうか。 私の処理系では、 ・プロトタイプ宣言でexternを付けて関数定義でstaticを付ける、 ・staticを付けた関数を他のソースファイルで呼ぶ、 などの明らかに矛盾する場合は、コンパイルエラーになります。 でも、extern単独での役割はなさそうです。 他の処理系でも同じでしょうか。 (main等省略)

  • 分割コンパイルについて

    現在分割コンパイルが分からずに苦戦しています。 下記のリストは構造体を使わなければコンパイラを通すことができましたが、 使うとなぜか通りません。 あれこれ試しましたがどうしても分かりません。 何がおかしいのでしょうか? *define.hで全てのファイルへの定義や宣言を行わせています。 ////////////// //Main.cpp ////////////// #include <stdio.h> #include <conio.h> #include "define.h" int main( void ){ Tmp[0].c = 15; printf("a: %d\n", a); printf("b: %d\n", b); printf("c: %d\n", Tmp[0].c); printf("NUM:%d\n", NUM); aaa(); bbb(); getch(); return 0; } ////////////////// // A.cpp ///////////////// #include <stdio.h> #include "define.h" void aaa( void ){ printf("a: %d\n", a); printf("b: %d\n", b); printf("c: %d\n", Tmp[0].c); printf("NUM:%d\n", NUM); } ////////////////// // B.cpp ///////////////// #include <stdio.h> #include "define.h" void bbb( void ){ printf("a: %d\n", a); printf("b: %d\n", b); printf("c: %d\n", Tmp[0].c); printf("NUM:%d\n", NUM); } ////////////////// // define.cpp ///////////////// #include "define.h" int a = 10; int b = 20; struct Parameter { int c; }; struct Parameter Tmp[NUM]; ////////////////// // define.h ///////////////// #define NUM 100 extern int a; extern int b; extern struct Parameter Tmp[NUM]; void aaa( void ); void bbb( void );

  • 別のファイルの値を得るには?

    ファイルを分割して関数を別のファイルにおいたのですが値を返してもらおうとしても帰ってきません どのようにしたら関数の値を得られますか? 大体このような感じですね ---main.cppの内容--- #include <stdio.h> #include "betu.h" void main( void ){ printf( "%d" , a ); } ---betu.hの内容--- static int a; void betu( void ); ---betu.cppの内容--- void betu( void ){ a = 5; }

  • C言語プログラミングについて

    #include <stdio.h> int main(void) { printf("hello,world\n"); } □■□■□■□■□■□■□■□■□■□■□■□■□■□■□■□■ #include <stdio.h> int main(void) { printf("hello"); printf(",world"); printf("\n"); } 上の2つのプログラムをコンパイルするとどのような違いが生じるんですか??printfってどんな働きをするんですか?

  •  現在、私はC言語を学んでいます。

     現在、私はC言語を学んでいます。  プログラミングの初期の初期の問題なんですが、 「Hello World」という有名なプログラムがありますよね? それについての質問です。 #include<stdio.h> main() { printf("Hello World"); return 0; } も #include<stdio.h> main(void) { printf("Hello World"); return 0; } も #include<stdio.h> int main() { printf("Hello World"); } もちゃんと表示できます。 ここで質問です。 int main(void) int main() main() main(void) はどう違うんですか? あと、 return 0; はあっても無くてもいいようなんですが どういう意味があるんでしょうか?

  • C言語のtypedefの質問

    Cビギナーです。 私のプログラムが長くなるのは、 ファイルの分割をしてないからだと知った今日この頃なのですが、 それを勉強するためにあるホームページを見ていたのですが、 次のようなサンプルプログラムがありました。 /* main.c */ #include <stdio.h> extern int func(int); typedef int (*pf)(int); extern pf getaddress(void); int main(void) { printf("%d\n",(getaddress())(4)); return 0; } /* sub.c */ static int func(int c) { return c*10; } typedef int (*pf)(int); pf getaddress(void) { return func; } ここで、typedef int (*pf)(int);の部分が分かりません。 intを(*pf)(int)で置き換えているのでしょうが、 それ自体がどういう意味か分かりません… どなたか教えて下さい。

  • 関数とポインタについて

    #include <stdio.h> void test(int *p); int main() { int i; test(&i); printf("%d",i); return 0; } void test( int *p) { static int k; k = 10; p = &k; } このようなプログラムを作って、void test()のkの値をmain関数で受け取りたいのですが、どのようにすればよいのかわかりません。 どなたか教えていただけませんか?

  • C言語について

    #include <stdio.h> int main(void) { printf("123456\tABC DEFGHIJK\n"); printf("2006/4/14\n"); printf("programing\n"); } のprintfをすべてputsに書き換えてコンパイル・実行すると、 #include <stdio.h> int main(void) { puts("123456\tABC DEFGHIJK\n"); puts("2006/4/14\n"); puts("programing\n"); } になると思うんですけど、そのputsを用いて上のprintfを用いたプログラムと同じ出力を得るにはどのようなプログラムに変えればいいのでしょうか?

専門家に質問してみよう