53

enum* を int* にキャストするコードを使用します。このようなもの:

enum foo { ... }
...
foo foobar;
int *pi = reinterpret_cast<int*>(&foobar);

コード (g++ 4.1.2) をコンパイルすると、次の警告メッセージが表示されます。

dereferencing type-punned pointer will break strict-aliasing rules

このメッセージをググったところ、厳密なエイリアシング最適化がオンになっている場合にのみ発生することがわかりました。次の質問があります。

  • この警告が表示されたままコードを残した場合、間違ったコードが生成される可能性はありますか?
  • この問題を回避する方法はありますか?
  • そうでない場合、ソース ファイル内から厳密なエイリアシングをオフにすることは可能ですか (すべてのソース ファイルに対してオフにしたくなく、このソース ファイルに対して別の Makefile ルールを作成したくないため) )?

はい、実際にはこの種のエイリアシングが必要です。

4

5 に答える 5

59

順番に:

  • はい。GCC は、ポインターがエイリアスできないと想定します。たとえば、一方を割り当ててから他方から読み取ると、GCC は最適化として、読み取りと書き込みの順序を変更することがあります。これは製品コードで発生するのを見たことがありますが、デバッグするのは快適ではありません。

  • いくつかの。ユニオンを使用して、再解釈する必要があるメモリを表すことができます。を使用できますreinterpret_castchar *メモリを再解釈するポイントでvia をキャストできます-char *何でもエイリアスできると定義されています。を持つタイプを使用できます__attribute__((__may_alias__))。-fno-strict-aliasing を使用して、エイリアシングの仮定をグローバルにオフにすることができます。

  • __attribute__((__may_alias__))使用される型については、おそらく、コードの特定のセクションの仮定を無効にするのに最も近い方法です。

特定の例では、列挙型のサイズが正しく定義されていないことに注意してください。GCC は通常、それを表すために使用できる最小の整数サイズを使用するため、列挙型へのポインターを整数として再解釈すると、結果の整数に初期化されていないデータ バイトが残る可能性があります。そうしないでください。適切な大きさの整数型にキャストしないのはなぜですか?

于 2010-11-12T09:33:03.730 に答える
11

しかし、なぜあなたはこれをしているのですか?sizeof(foo) != sizeof(int) の場合は壊れます。列挙型が整数に似ているからといって、それが整数として格納されるわけではありません。

そうです、「潜在的に」間違ったコードを生成する可能性があります。

于 2010-11-12T09:29:30.117 に答える
5

この回答を調べましたか?

厳密なエイリアシング ルールにより、この設定は違法になり、関連のない 2 つの型が同じメモリを指すことはできません。char* だけがこの特権を持っています。残念ながら、この方法でコーディングすることはできます。警告が表示される可能性がありますが、正常にコンパイルできます。

于 2010-11-12T09:25:14.137 に答える
3

Strict aliasing はコンパイラ オプションであるため、makefile からオフにする必要があります。

はい、正しくないコードが生成される可能性があります。コンパイラは事実上、foobarpiが結合されていないと仮定し、変更され*piても変更されないと仮定しfoobarます。

既に述べたように、static_cast代わりに使用してください (ポインターは使用しません)。

于 2010-11-12T09:35:17.477 に答える