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
このメッセージをグーグルで検索したところ、厳密なエイリアスの最適化がオンになっている場合にのみ発生することがわかりました。次の質問があります。
そして、はい、実際にこの種のエイリアシングが必要です。
順番に:
はい。 GCCは、ポインターがエイリアスできないと想定します。たとえば、一方から割り当ててから他方から読み取る場合、GCCは最適化として読み取りと書き込みを並べ替えることができます。これは実稼働コードで発生するので、デバッグするのは好ましくありません。
いくつか。ユニオンを使用して、再解釈する必要があるメモリを表すことができます。 _reinterpret_cast
_を使用できます。メモリを再解釈する時点で_char *
_を介してキャストできます。_char *
_は何でもエイリアスできると定義されています。 __attribute__((__may_alias__))
を持つ型を使用できます。 -fno-strict-aliasingを使用して、エイリアシングの仮定をグローバルにオフにできます。
使用される型の__attribute__((__may_alias__))
は、おそらくコードの特定のセクションの仮定を無効にするのに最も近いものです。
特定の例では、enumのサイズが正しく定義されていないことに注意してください。 GCCは通常、それを表現するために使用できる最小の整数サイズを使用するため、enumへのポインターを整数として再解釈すると、結果の整数に初期化されていないデータバイトが残る可能性があります。それをしないでください。なぜ適切に大きな整数型にキャストしないのですか?
しかし、なぜあなたはこれをしているのですか? sizeof(foo)!= sizeof(int)の場合は破損します。列挙型が整数に似ているからといって、それが1つとして格納されるわけではありません。
そのため、「潜在的に」間違ったコードを生成する可能性があります。
次のコードを使用してデータをキャストできます。
template<typename T, typename F>
struct alias_cast_t
{
union
{
F raw;
T data;
};
};
template<typename T, typename F>
T alias_cast(F raw_data)
{
alias_cast_t<T, F> ac;
ac.raw = raw_data;
return ac.data;
}
使用例:
unsigned int data = alias_cast<unsigned int>(raw_ptr);
この答え を調べましたか?
厳密なエイリアスルールにより、このセットアップは無効になり、2つの無関係なタイプが同じメモリを指すことはできません。 char *のみがこの特権を持っています。残念ながら、この方法でコーディングすることはできますが、警告が表示される場合がありますが、コンパイルは正常に完了します。
厳密なエイリアスはコンパイラオプションであるため、メイクファイルから無効にする必要があります。
そして、はい、それは不正確なコードを生成する可能性があります。コンパイラは、foobar
とpi
が結合されていないと効果的に想定し、*pi
は、foobar
が変更されても変更されません。
既に述べたように、static_cast
代わりに(およびポインターなし)。