2009年07月27日

定義宣言と参照宣言

C の規格に関するちょっとした話です。

今まで、extern が付いていない最上位宣言での変数宣言(グローバル変数)は、全て定義宣言になるのだと思っていたのですが、厳密には異なるそうです。
int x;         /* (1) */
int y = 0; /* (2) */
extern int x; /* (3) */

(1) と (2) は、単に初期値が与えられているかいないかだけの違いで、どちらも定義に見えます。

ところが、厳密には (2) だけが定義宣言で、(1) は仮定義という扱いになるのだそうです。

つまり、extern が付いていないことと、初期値が与えられていることの 2 つが、定義宣言の条件なのだそうです。

仮定義されたシンボルは、他に定義宣言が存在しなければ、真の定義になるそうです。

というわけで、以下のプログラムは、一見奇妙に見えますが合法ですし、実際にコンパイルして実行できます。
int x;         /* 仮定義はいくつあっても規格合致 */
int x;
int x;
int x;
extern int x;
extern int x;
extern int x;
int x = 0; /* 定義宣言は一つだけ */

int main()
{
return x;
}
これを例えば、どれか一つの宣言の型を変更したり、初期値を与えたりすると、当然のことながら定義宣言が 2 つ以上になってしまうのでコンパイルが通りません。
int x;
float x; /* エラー ! */
...
int x = 0;
int x = 1; /* エラー ! */

ちなみに C++ では最上位変数の仮定義の仕様は廃止され、真の定義扱いされるそうです。

実際に試してみたところ、上記プログラム (拡張子は .c で) は、gcc では -Wall -ansi -pedantic-errors、cl.exe では /W4 /WX をつけても無警告でコンパイル & 実行できますが、(拡張子を .cpp に変えて) g++/cl.exe (VC++ 2008) では再定義のエラーがたくさん出てコンパイル通りません。

参考文献 : S・P・ハービソン 3 世とG・L・スティール・ジュニアの C リファレンスマニュアル, pp 126-128,131

http://www.amazon.co.jp/dp/4434124234

トラックバックURL

トラックバック一覧

1. C言語での変数の実体の割り付けられかた  [ KMC Staff Blog ]   2009年07月28日 10:01
定義宣言と参照宣言の話に関連して、実際にこのコードをコンパイルして、変数がどう割り当てられるかをみてみましょう。 v.c >| int x; /* (1) */ int y = 0; /* (2) */ int z = 1; /* (3) */ extern int x; /* (4) */ || gcc -S v.c || .comm x,4,4 || .global y...

コメントする

名前
URL
 
  絵文字
 
 
記事検索
最新コメント
アクセスカウンター
  • 今日:
  • 昨日:
  • 累計:

QRコード
QRコード