7

C/C++ strict aliasing に関するこの記事を読みました。同じことがC++にも当てはまると思います。

私が理解しているように、厳密なエイリアシングは、パフォーマンスの最適化のためにコードを再配置するために使用されます。そのため、異なる (C++ の場合は関連のない) 型の 2 つのポインターが同じメモリ位置を参照することはできません。

これは、メモリが変更された場合にのみ問題が発生する可能性があるということですか? メモリ アラインメントに関する考えられる問題は別として。

たとえば、ネットワーク プロトコルの処理や逆シリアル化などです。動的に割り当てられたバイト配列があり、パケット構造体は適切に配置されています。reinterpret_cast私のパケット構造体にそれを渡すことはできますか?

char const* buf = ...; // dynamically allocated
unsigned int i = *reinterpret_cast<unsigned int*>(buf + shift); // [shift] satisfies alignment requirements
4

2 に答える 2

7

ここでの問題は、厳密なエイリアシングではなく、構造表現の要件です。

charまず、 、signed char、またはunsigned charの型 (あなたの場合は) の間でエイリアスを作成しても安全です。これにより、型unsigned intを使用して定義されている限り、独自のメモリ コピー ループを作成できます。これは、 charC99 の次の言語 (§6.5):

 6. 格納された値にアクセスするためのオブジェクトの有効な型は、オブジェクトの宣言された型です (存在する場合)。[脚注: 割り当てられたオブジェクトには型が宣言されていません] [...] memcpy または memmove を使用して型が宣言されていないオブジェクトに値がコピーされた場合、または文字型の配列としてコピーされた場合、変更されたオブジェクトの有効な型そのアクセスと、値を変更しない後続のアクセスの場合、値がコピーされるオブジェクトの有効な型です (存在する場合)。宣言された型を持たないオブジェクトへの他のすべてのアクセスでは、オブジェクトの有効な型は、単にアクセスに使用される左辺値の型です。

 7. オブジェクトは、次のタイプのいずれかを持つ左辺値式によってのみアクセスされる保存された値を持つものとします。

  • オブジェクトの有効な型と互換性のある型、
  • [...]
  • 文字タイプ。

同様の言語が C++0x ドラフト N3242 §3.11/10 にありますが、オブジェクトの「動的型」がいつ割り当てられるかは明確ではありません (動的型が何であるかについてのさらなる参照をいただければ幸いですPOD オブジェクトが適切な配置で char 配列としてコピーされた char 配列)。

そのため、エイリアシングはここでは問題になりません。ただし、標準を厳密に読むと、C++ の実装では の表現を自由に選択できることがわかりunsigned intます。

1 つのランダムな例として、unsigned ints は 4 バイトで表され、8 つのパディング ビットが散在する 24 ビット整数である可能性があります。これらのパディング ビットのいずれかが特定の (一定の) パターンと一致しない場合、それはトラップ表現と見なされ、ポインターの逆参照はクラッシュを引き起こします。これは実装の可能性がありますか?おそらくそうではありません。しかし、歴史的には、パリティ ビットやその他の奇妙な機能を備えたシステムが存在したため、標準を厳密に読み取ることによってunsigned int、ネットワークから に直接読み取ることはコーシャではありません。

現在、ビットのパディングの問題は、今日のほとんどのシステムでほとんどが理論的な問題ですが、注目に値します。PC ハードウェアに固執する場合は、特に心配する必要はありません (ただし、ntohls を忘れないでください - エンディアンは依然として問題です!)

もちろん、構造はそれをさらに悪化させます - アラインメント表現はプラットフォームに依存します。私は、すべてのタイプのアライメントが 1 である組み込みプラットフォームで作業しました。構造体にパディングが挿入されることはありません。これにより、複数のプラットフォームで同じ構造定義を使用すると、矛盾が生じる可能性があります。データ構造メンバーのバイト オフセットを手動で計算して直接参照するか、コンパイラ固有のアラインメント ディレクティブを使用してパディングを制御できます。

そのため、ネットワーク バッファーからネイティブの型または構造体に直接キャストする場合は注意が必要です。しかし、この場合、エイリアシング自体は問題になりません。

于 2011-09-06T14:48:29.723 に答える
0

実際、このコードには、ed 整数ポインターを逆参照する時点で既に UB があり、reinterpret_cast厳密なエイリアス規則を呼び出す必要さえありません。それだけでなく、注意を怠ると、パケット構造を直接再解釈すると、構造体のパッキングとエンディアンに応じてあらゆる種類の問題が発生する可能性があります。

これらすべてと、既に UB を呼び出していることを考えると、複数のコンパイラで「動作する可能性が高い」と思われ、その (おそらく測定可能な) リスクを自由に取ることができます。

于 2011-09-06T14:49:04.663 に答える