厳格なポインターエイリアシング:「揮発性」ポインター/参照を介したアクセスはソリューションですか?
-
24-10-2019 - |
質問
のかかと 特定の問題, 、自己回答とそれに対するコメント、それが適切な解決策、回避策/ハック、または単に間違っているかどうかを理解したいと思います。
具体的には、コードを書き直しました。
T x = ...;
if (*reinterpret_cast <int*> (&x) == 0)
...
として:
T x = ...;
if (*reinterpret_cast <volatile int*> (&x) == 0)
...
とともに volatile
ポインターの予選。
その治療を想定してみましょう T
なので int
私の状況では理にかなっています。これはaを介してアクセスしますか volatile
参照ポインターエイリアシングの問題を参照しますか?
参照のために、仕様から:
注:揮発性は、オブジェクトの値が実装によって検出されない手段によって変更される可能性があるため、オブジェクトを含む積極的な最適化を回避するための実装のヒントです。詳細なセマンティクスについては、1.9を参照してください。一般に、揮発性のセマンティクスは、C ++ではCと同じように同じであることを目的としています。
編集:
上記のコードは、少なくともGCC 4.5で私の問題を解決しました。
解決
揮発性は、ここで未定義の行動を避けるのを助けることができません。だから、それがGCCであなたのために働いているなら、それは運です。
Tがポッドであると仮定しましょう。次に、これを行う適切な方法です
T x = …;
int i;
memcpy(&i,&x,sizeof i);
if (i==0)
…
そこには!厳密なエイリアシングの問題やメモリアライメントの問題はありません。 GCCは、本質的な関数としてMemcpyを処理します(この場合、関数呼び出しは挿入されていません)。
他のヒント
揮発性は、ここで未定義の行動を避けるのを助けることができません。
まあ、何についても volatile
標準ではやや不明です。私はあなたの答えにほとんど同意しましたが、今は少し反対したいと思います。
何を理解するために volatile
つまり、ほとんどの人、特に一部のコンパイラライターにとっては標準が明確ではありません。考える方が良いです:使用するとき volatile
(そして、たったの場合)、C/C ++は非常に高レベルのアセンブリです.
に書くとき volatile
lvalue、コンパイラは店を発行します。volatile
原子を意味しません)。
に書くとき volatile
LValue、コンパイラは、十分でない場合は負荷または複数の負荷を発行します。
もちろん、明示的な負荷やストアがない場合、コンパイラはロードまたはストアを意味する指示を発行するだけです。
Sellibitzeは最高の解決策を与えました: 使用する memcpy
少し再解釈のために。
しかし、メモリ領域へのすべてのアクセスがで行われた場合 volatile
lvalues、 厳密なエイリアシングルールが適用されないことは完全に明らかです. 。これはあなたの質問に対する答えです。