[2378] Re:ポインタ完全制覇の質問
投稿者:774RR
2024/05/24 13:10:59
この辺 C と C++ で微妙に仕様が違うところピンポイントで踏み抜いているのでいろいろわけわからんことになっています。今この瞬間には C 言語仕様書 JIS X 3010 ならびに C++ 言語仕様書 JIS X 3014 にアクセスできないので記憶とコンパイラの挙動だけで話をします。
サンプルソース tentative.c ないしは tentative.cpp
static int a[];
static int a[4];
unsigned long f() { return sizeof a; }
C の場合
変数定義で要素数を書かない場合(上記 static int a[]; が該当)には当該変数は不完全型な仮定義 (tentative definition) になる・・・と言いたいところなんですが static がある場合には仮定義にならず一発定義になります。また、要素数についてはコンテキスト次第で解釈が変わってよいところです。とあるコンテキストではこれを int a[1]; と読んでよいことになっています。別のコンテキストではこれを不完全型と読んでよい(要素数未知)ことになっています。詳細は言語仕様書を読まないと出てきません(覚えていません)。
cygwin64 にて
$ gcc --version
gcc (GCC) 11.4.0 // 以下略
$ gcc -W -Wall -pedantic -O -S tentative.c
tentative.c:1:12: error: array size missing in 'a'
1 | static int a[];
| ^
tentative.c:2:12: error: conflicting types for 'a'; have 'int[4]'
2 | static int a[4];
| ^
tentative.c:1:12: note: previous declaration of 'a' with type 'int[1]'
1 | static int a[];
| ^
tentative.c:1:12: warning: 'a' defined but not used [-Wunused-variable]
$
ということで gcc-11.4.0 は先の例を static int a[1]; と読んでいます。本当にそう読んだのかアセンブラコードで確認したいところですが、残念ながらコンパイルエラーになっているので確かめられません。
C++ の場合
C にあった仮定義がなくなっている関係で int a[]; は個数不定な「変数定義」になります。なのでこの時点でコンパイルエラー。更に ODR (one definition rule) も適用され int a[4]; と矛盾しここでもエラーになります。
$ g++ -W -Wall -pedantic -O -S tentative.cpp
tentative.cpp:1:12: error: storage size of 'a' isn't known
1 | static int a[];
| ^
$
あるいは Visual Studio 2019 の VC++ だと
D:\work\tmp>cl -W4 -Ox -c tentative.c
Microsoft(R) C/C++ Optimizing Compiler Version 19.29.30154 for x64
Copyright (C) Microsoft Corporation. All rights reserved.
tentative.c
tentative.c(1): error C2133: 'a': サイズが不明です。
D:\work\tmp>cl -W4 -Ox -c tentative.cpp
Microsoft(R) C/C++ Optimizing Compiler Version 19.29.30154 for x64
Copyright (C) Microsoft Corporation. All rights reserved.
tentative.cpp
tentative.cpp(1): error C2133: 'a': サイズが不明です。
tentative.cpp(2): error C2086: 'int a[]': 再定義されました。
tentative.cpp(1): note: 'a' の宣言を確認してください
tentative.cpp(4): error C2070: 'int []': sizeof オペランドが正しくありません。
というわけで不完全型な変数定義になる static int a[]; は書いちゃダメ、コンパイラ次第で挙動が違う、でしょう。まあコンパイルエラーになってくれるので、実行するまでわからないという最恐な事態には陥らなくて済みそうです。