2006-12-18
RiSKさんのブログのコメント欄でやたらと盛り上がってしまったのですが、char型またはwchar_t型の配列を文字列リテラルで初期化する場合、配列の要素数より(初期化子である)文字列リテラルの文字数の方が少ないとき、ナル文字以降の値はどうなるのか、という話題です。実際のコードで示すと、次のような場合です。
char str[5] = "abc";
C言語であれば、ナル文字以降は '\0' で初期化されることが、規格上はっきりと規定されています。つまり、上のコードは、
char str[5] = { 'a', 'b', 'c', '\0', '\0' };
と等価になります。
C++でも、この辺りの事情は同じだと思っていました。実際、私が知る限りの処理系では、C言語と同じように振る舞います。ところが、C++の規格であるJIS X3014:2003を読むと、ナル文字以降が '\0' になることが保証されているようには、どうしても読み取れないのです。
配列の要素より初期化子の個数が少ない場合の振る舞いは、8.5.1 集成体の項で規定されています。ですから、{} で囲んだ初期化子の場合には、明示的に初期値を与えていない要素は '\0' になります。しかし、それより一階層上の8.5 初期化子の段落14には、
− 目的の型がchar型の配列又はwchar_t型の配列であって, 《初期化子》が文字列リテラルである場合については, 8.5.2で規定する。
− そうではなくて, 目的の型が配列の場合については, 8.5.1で規定する。
と書かれており、文字列リテラルで配列を初期化する場合には、8.5.1の規定は適用されないのです。
で、8.5.2には何が書かれているかというと、要約すれば、
- 文字列リテラルの各文字によって、配列の各要素が初期化される。
- 文字列リテラルの末尾には '\0' が付加されるので、それも初期値になる。
- 配列要素の個数より多い《初期値》があってはならない(C言語との互換性無し)。
という、非常にあっさりした内容しかありません。ここでは、配列の要素より《初期値》の方が少ない場合については言及されていないので、ナル文字以降の値が不定になるというよりは、そのような初期化は未定義の動作を引き起こすのではないかと思います。そして、結果として、未定義動作の振る舞いがC言語と同じになっている処理系が大多数を占めているのではないかと思います。
個人的には、C言語と同じ振る舞いになることがどこかで保証されていることを期待しているのですが、調べれば調べるほど、そうではない証拠ばかりが集まります。
どなたか詳しい方、実際はどうなのか教えてください。
Comment
↓
char str[10] = { 'a', 'b', 'c', '?0', '?0' };
ハッΣ(`Д´; サイズが倍になってる!?
コメントありがとうございます。
最初10にしていて、横長過ぎたので5に変えたんですけど、片方しか修正していませんでした。
直しておきます。