質問: (Msg*)(buff); ``` このコードにおける「オブジェクト」は`malloc()`によって確保されたものですが、これは私の考えでは特定の型に依存するものではないように思います。この場合も、何か特定の型に依存した解釈がなされるものでしょうか。
回答: 第三者読者の役に立つよう alias (別名)とは何かの解説から (TL;DR) ``` int i; int* p=&i; i=1; *p+=1; ``` [c](/questions/tagged/c "'c' のタグが付いた質問を表示") ではポインタ ([c++](/questions/tagged/c%2b%2b "'c++' のタグが付いた質問を表示") では参照も) を経由すると同一の記憶域(あえてメモリと書かない)に2つ以上の方法でアクセスできます。上記 `i` と `*p` がそれです。こういうのを alias と言います。 先のコードは無駄っぽいけど悪いことしてないように見える。では何が問題か? [c](/questions/tagged/c "'c' のタグが付いた質問を表示") はすごく古い言語なので、むかしむかしから維持されているコードではこの alias を(コンパイラから見て)ひどい使い方していることがあります。 ``` int aliastest(int i) { // int が 16bit と仮定する char* p=(char*)&i; // 無理やり型変換して char c=p[0]; p[0]=p[1]; p[1]=c; // 元変数を型違い alias で変更 return i; // char* の先に書き込んで int が変わることを期待してる } ``` 元の変数と違う型のポインタ経由のアクセスが1つあるだけでソース上アクセスしていないように見える変数が無節操に変わりうるとすると ``` int global_int; void func(double* p) { *p=1; // ここで global_int は変更されるのか否か otherfunc(global_int); } ``` もし `global_int` が変化する前提でしか最適化できないとしたら、コンパイラの実装者がどんなに頑張ってもポインタアクセスがあった時点で最適化のほとんどが適用できなくなります。 そのためアグレッシブな最適化をして良いパターンとダメなパターンをはっきり文章化して、コンパイラの実装者とコンパイラのユーザの両方に周知徹底させようという状況の1つが strict aliasing rule です。 以下引用元は JIS X 3010:2003 ([c99](/questions/tagged/c99 "'c99' のタグが付いた質問を表示")) もっと新しい版だと変更があるかも > > 6.5 式 の後ろのほう > > オブジェクトに格納された値に対するアクセスは、次のうちのいずれか1つの型を持つ左辺値によらなければならない。注釈(73)この列挙は、オブジェクトに別名を付けてもよい状況と、付けてはならない状況を規定するためのものである。 > > - オブジェクトの有効型と適合する型 > > - オブジェクトの有効型と適合する型の修飾版 > > - オブジェクトの有効型に対応する符号付き型又は符号無し型 > > - オブジェクトの有効型の修飾版に対応する符号付き型又は符号無し型 > > - メンバの中に上に列挙した型の1つを含む集成体型又は共用体型(再帰的に包含) > > - 文字型 > > > なので例えば - `int` と `unsigned int` と `volatile signed int` は alias 可能 - `struct foo_type { short member; };` と `signed short` は alias 可能 - `char` は任意の型と alias 可能 alias 可能とは、既に書いた通りアグレッシブな最適化を禁じるということです。 ではようやく回答 A1. アクセスは 3. の時点です > > 3.1 アクセス > > <実行時の動作>オブジェクトの値を読み取る、または変更すること。 > > 参考1.いずれか一方だけを意味する場合は”読み取る”または”変更する”という用語を使う > > > この例では alias できると規定されていない型なので規格違反(未定義動作)になるでしょう。 A2. 提示の部分コードだけだと「ポインタの型変換」はあっても、それを経由した「オブジェクトへのアクセス」はしていないので、それだけだと判断できないです。 > > 6.5 式 の後ろのほう > > 格納された値にアクセスするときのオブジェクトの有効型は(もしあれば)そのオブジェクトの宣言された型とする。注釈(72)割付オブジェクトは宣言された型をもたない。 > > 宣言された型を持たないオブジェクトへ、文字型以外の型をもつ左辺値を通じて値を格納した場合、左辺値の型をそのアクセスおよび格納された値を変更しないそれ以後のアクセスでのオブジェクトの有効型とする。 > > > リンク先の SO サンプルコードだと `struct Msg` の `unsigned int` なメンバにアクセスしていて(よってここでの「オブジェクトの有効型」は `unsigned int` )その後 alias 可能とされていない `uint32_t` で別名アクセスしているので違反です、と解説されています。 ちなみにオイラのサンプル `aliastest()` は `char` が alias 可能なのでプログラマが期待した通りの結果が得られるはず。得られないコンパイラは言語仕様逸脱ってことになるっす。