古いプログラムでは、unsigned char の配列を割り当ててデータ構造をバイトにシリアル化し、次のように int に変換しました。
*((*int)p) = value;
(p
は 、 はunsigned char*
保存value
する値です)。
これは問題なく動作しましたが、Sparc でコンパイルすると、不適切なアラインメントでメモリにアクセスしたために例外がトリガーされました。データ要素のサイズがさまざまであるため、p
すぐに整列されなくなり、基になる Sparc 命令で整列が必要な int 値を格納するために使用されるとエラーが発生したため、これは完全に理にかなっています。
これはすぐに修正されました (値を char-array にバイト単位で書き出すことにより)。しかし、私はこの構造を何年にもわたって多くのプログラムで問題なく使用してきたので、これについて少し心配しています。しかし、明らかに私はいくつかの C ルール (厳密なエイリアシング?) に違反しています。このケースは簡単に発見されましたが、おそらく違反は、コンパイラーの最適化などにより、より微妙な他のタイプの未定義の動作を引き起こす可能性があります。このような構造は、長年にわたって多くの C コードで見てきました。ハードウェアによって交換されるデータ構造を構造体として記述し (もちろん pack(1) を使用)、それらを h/w レジスタなどに書き込むハードウェア ドライバーを考えています。したがって、一般的な手法のようです。
したがって、私の質問は、まさに上記によって違反されたルールと、ユースケースを実現するための適切な C の方法 (つまり、unsigned char の配列へのデータのシリアル化) です。もちろん、すべての関数に対してカスタムのシリアル化関数を記述して、バイト単位で書き出すことができますが、面倒であまり効率的ではないように思えます。
最後に、一般に、このエイリアシング規則に違反することによって、悪影響 (アライメントの問題以外) が予想される可能性はありますか?