DTrace で const 指定が無視される件 - その2
色々弄繰り回しているうちに、はて const 修飾って言語仕様上どうなってたっけ?という根源的な問題に突き当たる。
hoge(const char* v1[], char const* v2[], char* const v3[])
上記の様に宣言された場合、コンパイラによって禁止される各引数へのアクセスは、v1 に関しては余裕でわかるけど、他の奴は全然予想と違う結果に。
っつーか、配列形式の宣言はよくわかんねー!ということで、ポインタ形式に展開してみる。
hoge(const char** v1, char const** v2, char* const* v3, char** const v4)
で、個々の const 修飾については:
- "char" に対する const 修飾なので、"v1[0][0] = 'a'" は禁止
- "char" への "*" に対する const 修飾なのだけど、何が禁止?
- "char*" への "*" に対する const 修飾なので、"v3[0] = NULL" は禁止
- v4 に対する const 修飾なので、"v4 = NULL" が禁止
じゃなかろうか?ということで、コンパイラを通してみると.... おぉ!v1, v3, v4 に関しては合っている!ってーことで、配列形式の v3 における const の修飾先は、引数名 v3 だと思っていたけど、実は配列っつーかポインタに掛かっているのね。
それと、v2 は v1 と同じ扱いだった。
実は、CTF ライブラリを直接叩いて色々やってみたところ、"char*" を const 修飾した型の文字列化では、"char const*" じゃなくて "char *const" が得られたので、「????」になっていたのだが、繋がって来た感じがする。
これまでの結果を踏まえつつ、ウンウン唸る事暫し。
これまでは、他の修飾要素(signed とか)と同様に、const は後ろに続く要素を修飾するものと考えていたのだけれど、どうも「先行要素を修飾する」と考えた方が辻褄があっている気がしてきた。
- "char const**" では "char" を修飾 → ** の先の改変が禁止
- "char* const*" では "char*" を修飾 → * の先の改変が禁止
- "char** const" では "char**" を修飾 → 変数そのものの改変が禁止
でもって、"const char**" は特殊ケースというか過去の亡霊というか、広く使われちゃっているので "char" を修飾するものとみなそう、ということだと考えると、比較的すっきりする感じ。
こういった細かいところが曖昧だったりするので、やっぱり ANSI の言語仕様を引っ張ってこないと駄目だなぁ、ということで、ISO の C 言語ワーキンググループのページから C99 の言語仕様を調達して確認。
....なんかこの仕様、C89 とか C95 仕様を前提に書いているっぽいなぁ。厳密な解釈に関しては微妙に記述を避けてるような気が。まぁ、いいか。
ついでと言ってはなんだけど、以下の記述が等価らしいことを知った。っつーか、"[const]" なんて記法が通ることも知らなかったよ .... orz
hoge(char** const v); hoge(char* v[const]);
人生日々勉強だなぁ。