2013-03-21 [C] 外部変数(グローバル変数)の定義(仮定義) ================================================================================ 何のキーワードもつけない外部変数を 2 つのモジュールで定義すると、片一方は自動的 に extern がついた扱いになる。 ただし、2 つとも初期値を設定すると、リンクで二重定義となりエラー。 これって C の仕様かな。それとも、gcc 固有の拡張か? (gcc 3.4) どうやら、C 言語の仕様。 仮定義というもの。リンケージ時に仮定義の中のひとつが定義になる。 ヘッダー・ファイルで外部変数を定義するときに、初期値をつけないことにしておけば、 extern をつけたり、つけなくしたりするための条件コンパイルや、マクロ定義は必要なく なるなあ。 □ global_test.c --- #include <stdio.h> #include <stdlib.h> void func(void); int global = 1234; // (1) int main(void) { printf("main: %d\n", global); func(); return EXIT_SUCCESS; } --- □ global_test2.c --- #include <stdio.h> #include <stdlib.h> void func(void); int global; // (2) void func(void) { printf("func: %d\n", global); } --- □ 実行結果 --- main: 1234 func: 1234 --- □ nm コマンドの結果 --- 00402000 D _global --- (1)と(2)の組合せで、nm コマンドの結果(シンボル・タイプ) ------------------- ----------- ------------------ (1)\(2) int global; int global = 1234; ------------------- ----------- ------------------ int global; B D int global = 1234; D (*) ------------------- ----------- ------------------ (*) リンケージでエラー(multiple definition of `global') nm コマンドは、指定されたライブラリ内に存在するシンボルのリストを表示する。 シンボル・タイプは以下のとおり。 T (コードセクション内の普通の定義) D (初期化されたデータセクション) B (初期化されないデータセクション) U (未定義。シンボルはライブラリによって使われているが、ライブラリ内では定義 されていない) W (weak. もしも他のライブラリも同じシンボルを定義している場合、その定義によ りオーバーライドされる) 参考: Program Library HOWTO > 5. 雑録 > 5.1. nm コマンド http://archive.linux.or.jp/JF/JFdocs/Program-Library-HOWTO/miscellaneous.html ついでに、 JIS X3010「プログラム言語C」6.9.2 外部オブジェクト定義 の例1 を示す。 □ global_tes3.c --- int i1 = 1; // 定義、外部結合 static int i2 = 2; // 定義、内部結合 extern int i3 = 3; // 定義、外部結合 int i4; // 仮定義、外部結合 static int i5; // 仮定義、内部結合 int i1; // 正しい仮定義、前の定義を参照する //int i2; // 前に内部結合を持つ定義があるため、結合の不一致が生じ、 // "6.2.2 識別子の結合" によって動作は未定義となる int i3; // 正しい仮定義、前の定義を参照する int i4; // 正しい仮定義、前の定義を参照する //int i5; // 前に内部結合を持つ定義があるため、結合の不一致が生じ、 // "6.2.2 識別子の結合" によって動作は未定義となる extern int i1; // 外部結合を持つ前の定義を参照する extern int i2; // 内部結合を持つ前の定義を参照する extern int i3; // 外部結合を持つ前の定義を参照する extern int i4; // 外部結合を持つ前の定義を参照する extern int i5; // 内部結合を持つ前の定義を参照する --- □ global_test4.c --- //int i1 = 1; // 定義、外部結合 ※二重定義になるのでコメントアウト static int i2 = 2; // 定義、内部結合 //extern int i3 = 3; // 定義、外部結合 ※二重定義になるのでコメントアウト int i4; // 仮定義、外部結合 static int i5; // 仮定義、内部結合 int i1; // 正しい仮定義、前の定義を参照する //int i2; // 前に内部結合を持つ定義があるため、結合の不一致が生じ、 // "6.2.2 識別子の結合" によって動作は未定義となる int i3; // 正しい仮定義、前の定義を参照する int i4; // 正しい仮定義、前の定義を参照する //int i5; // 前に内部結合を持つ定義があるため、結合の不一致が生じ、 // "6.2.2 識別子の結合" によって動作は未定義となる extern int i1; // 外部結合を持つ前の定義を参照する extern int i2; // 内部結合を持つ前の定義を参照する extern int i3; // 外部結合を持つ前の定義を参照する extern int i4; // 外部結合を持つ前の定義を参照する extern int i5; // 内部結合を持つ前の定義を参照する --- □ nm コマンドの結果 --- 00402004 D _i1 00402008 d _i2 00402000 d _i2 0040200c D _i3 004040b0 B _i4 00404020 b _i5 00404010 b _i5 --- シンボル・タイプで、小文字はそのシンボルがローカルであることを意味し、大文字はそ のシンボルがグローバル (外部定義) であることを意味する。 以上