2013-06-17 23 views
9

私は32ビットウィンドウから64ビットへの移植を行っています。アライメントされていないポインタが参照ではないという警告が表示されるのはなぜですか?

void FuncA(double &x) 
{ 
    x = 0; 
} 

void FuncB(double *x) 
{ 
    *x = 0; 
} 

#pack(1) 

struct 
{ 
    char c; 
    double x; 
} MyStruct; 

#pack(); 

void MyFunc() 
{ 
    MyStruct M; 
    FuncA(M.x); // This is OK 
    FuncB(&M.x); // This generates a warning C4366 
} 

充填構造体の次の警告を生成するのメンバーとFuncBを呼び出す、64ビットを標的VS2010 SP1の下にコンパイル。

警告C4366:単項 '&' 演算子の結果は​​を呼び出すことはしません

のに対して整列していないかもしれません。私は両方のケースがほぼ同じコードにコンパイルされていると思っていたでしょう。参照が同等のポインタよりも整列の問題から安全かどうか、またはMSVCが単に警告を出していないかどうかプロジェクトでは、構造体のパッキングが維持される必要があり、そう私の選択肢はFuncB

void FuncB(__unaligned double *x) 
{ 
    *x = 0; 
} 

または単純にすべてのそのような場合に​​を使用する

に変更するかのいずれかです。後者はより移植性が高いので好ましいでしょうが、私はそれがうまくいくと思っています。あるいは、リファレンスケースの警告の欠如は単にコンパイラの欠点です。

編集:このエラーのMicrosoftヘルプのエントリはhereです。 __unalignedヘルプは、この警告に従わないと、Itaniumプロセッサで例外がスローされることを示唆しています。 MSDNについてさらに詳しく調べると、there may be issues surrounding unaligned referencesが示唆されます。現在のユーザーには問題はありませんが、将来的にItaniumアーキテクチャーが広く使用されるようになれば、サポートの悪夢を設定する可能性があります。ポインターと__unalignedキーワードを避けるために、パック構造を使用するすべての関数に特定のラッパーを追加するようになりました。

答えて

7

リファレンスとポインタはほぼ同じものです(言い換えればボンネットの下にあります)ので、安全性の観点からは違いはありません。 C++環境の外部に渡すことはできないので(おそらく私はそれが単なる見落としであると思う傾向があるが)、おそらく見落としが多い、あるいはコンパイラが参照にあまり心配していないかもしれない。

doubleの値の範囲で反復したい場合は、ポインタがパフォーマンスに使用される可能性がより高いため、コンパイラはポインタの方が関係している場合があります(たとえば、構造体自体よりも多くの領域を割り当てますそれ以降にさらにdoubleの値を格納している場合) - 参照を使用してその値を行うことはできません。アラインされていないアクセスは少なくともアライメントされたアクセスよりも遅いため、これはパフォーマンスに影響を与える可能性があります。システムによっては、OSトラップが発生し、アライメントされていないアクセスをOSが単に「あなたのプログラムによってアラインされていないアクセスが発生した、私はそれを殺している」と言うだけです)。

アライメントされていないアクセスではデータをアトミックに更新しない可能性があるため、マルチスレッドにも問題があります。もちろん、スレッド間で共有されるデータにはstd::atomicなどを使用する必要があります。

x86は、アラインされていないアドレスからdoubleを完全に読み取ることができます。私はItaniumはそうではないと思っていますが、統計的に言えば、あなたはそのプロセッサを使用しないと思われます。 Alphaなどの他の古いアーキテクチャでは、アライメントされていないメモリを読み取る際に問題が発生することがあります。

+3

アンアラインドアクセスが整列アクセスより遅い、そしてマルチスレッド環境では、他の望ましくない効果を有することができる(インテルに整列読み出し/書き込みがアトミックであるが、アラインされていないアクセスのためにない場合、その2つのスレッドが値1および2書き込みと^ 31を同じ変数に置き、値を読み取るスレッドが値を揃えた場合は、1または2^31;非アライメントのアクセスであることが保証されます)。他のプラットフォーム(SPARC)では、アラインされていない読み取り/書き込みを処理できず、プロセッサはトラップします。 –

+0

アライメントの悪いアクセスが遅いことを説明するために、「ここではポインタの方が参考になると思うのはなぜか」を更新しました。私はSPARC用のWindowsのバージョンについて認識していないので、その動作は重要ではないと考えています.64ビットARMもまだWindows用には利用できません。 X86とItaniumを残しています... –

+0

C++コンパイラの警告と境界整列されていないアクセスに関するコメントでしたが、sparcの代わりにアルファベットを使用したい場合はアルファ版では複数のWindows OSが動作していますが、新しいバージョンの場合はわかりません。編集について...ああ。答えは以前より良かった! –

関連する問題