1

Lint ( http://www.gimpel.com/html/pub/msg.txtの 740 ) から、union へのポインターを unsigned へのポインターにキャストしないように警告するという警告を受け取りました。長いです。互換性のない型をキャストしていることはわかっていたので、 reinterpret_cast を使用していましたが、それでも警告が表示されて驚きました。

例:

// bar.h
void writeDWordsToHwRegister(unsigned long* ptr, unsigned long size)
{
  // write double word by double word to HW registers 
  ...
};

// foo.cpp
#include "bar.h"

struct fooB
{
  ...
}

union A 
{
  unsigned long dword1;
  struct fooB; // Each translation unit has unique content in the union
  ...
}

foo()
{
  A a;
  a = ...; // Set value of a

  // Lint warning
  writeDWordsToHwRegister(reinterpret_cast<unsigned long*> (&a), sizeof(A));

  // My current triage, but a bad one since someone, like me, in a future refactoring 
  // might redefine union A to include a dword0 variable in the beginning and forget
  // to change below statement.      
  writeDWordsToHwRegister(reinterpret_cast<unsigned long*> (&(a.dword1)), sizeof(A)); 
}

私がそれを行っていた理由と、それを最良の方法で解決する方法を正確に脇に置いて(インターフェイスのvoid *とwriteDWordsToHwRegisterのunsigned long *にキャストしますか?)、Lint警告を読むと、一部のマシンではcharへのポインターに違いがあることが説明されましたと単語へのポインタ。誰かがその違いがどのように現れるかを説明し、これらの違いを示すいくつかのプロセッサの例を挙げてもらえますか? アラインメントの問題について話しているのですか?

組み込みシステムであるため、エキゾチックな社内コアを使用しているため、悪いことが起こる可能性がある場合は、おそらくそうなるでしょう。

4

5 に答える 5

3

コンパイラーは、Asへのポインターとlongsへのポインター(通常はdwordsですが、この場合は単にwordsである可能性があります)が同じメモリー領域を指していないことを前提としています。これにより、多くの最適化が可能になります。たとえば、A *を指す場所に書き込む場合、long*からの以前のロードを更新する必要はありません。これはエイリアシングと呼ばれます-この場合、エイリアシングの欠如です。しかし、あなたの場合、生成されたコードが実際には期待どおりに機能しない可能性があるという影響があります。

これを移植可能にするには、最初にデータをcharバッファーを介してコピーする必要があります。これには、アンチエイリアシング規則の例外があります。charsはすべてのエイリアスです。したがって、charを見るとき、コンパイラはそれが何でも指すことができると想定する必要があります。たとえば、次のようにすることができます。

char buffer[sizeof(A)];
// chars aliases with A
memcpy(buffer, reinterpret_cast<char*>(&a), sizeof(A));
// chars also aliases with unsigned long
writeWordsToHwRegister(reinterpret_cast<unsigned long*> (buffer), sizeof(A)); 

さらに質問がある場合は、「厳密なエイリアシング」ルールを調べてください。これは実際にはかなりよく知られている問題です。

于 2012-07-20T09:44:49.650 に答える
3

一般に、ポインター間の違いは、型が異なればサイズが異なるという事実を指します。pointer+=1 を実行すると、p が char へのポインターであるか、word へのポインターであるかによって、異なる結果が得られます。

于 2012-07-20T09:39:22.150 に答える
2

一部のマシンでは、char へのポインターと word へのポインターが実際には異なることを私は知っています。

これが当てはまるマシンがいくつかあります (主に DSP ですが、古い DEC マシンもこれを行っていたと思います)。

つまり、これらのマシンのいずれかで何かを char に再​​解釈_キャストすると、ビット パターンは必ず有効になります。

ユニオンへのポインターは理論上、その任意のメンバーを指すことができるため、ユニオン ポインターを使用して char または単語をポイントできるようにするためには、ユニオン ポインターに何かを含める必要があることを意味します。つまり、reinterpret_casting は、有効なアドレスの一部であるかのように使用されているコンパイラにとって何かを意味するビットになってしまうことを意味します。

たとえば、ポインターが 0xfffa の場合、'a' は、unionptr->charmember (おそらく何もしない) と言うときに何をすべきかを理解するためにコンパイラーが使用する魔法であり、unionptr->wordmember (おそらく使用する前に 3ff に変換してください)、これを long * に再解釈_キャストすると、再解釈_キャストはビット パターンに何もしないため、まだ fffa があります。

これで、(たとえば) 3ff である必要があるのに対し、コンパイラが fffa を含む long へのポインターであると見なすものがあります。

これは厄介なクラッシュにつながる可能性があります。

于 2012-07-20T09:51:47.963 に答える
1

char *はバイトアラインメント(何でも!)できますが、long *は通常、最新のプロセッサでは4バイト境界にアラインメントする必要があります。

より大きなアイアンでは、位置がずれた境界でロングにアクセスしようとすると、クラッシュが発生します(* nixのSIGBUSなど)。ただし、一部の組み込みシステムでは、検出を困難にする奇妙な結果を静かに得ることができます。

これはARM7で発生するのを見てきましたが、何が起こっているのかを確認するのは困難でした。

于 2012-07-30T07:14:45.360 に答える
0

なぜcharへのポインタが関係していると思うのかわかりません-ユニオンAへのポインタをlongへのポインタにキャストしています。最善の修正は、おそらく変更することです。

void writeWordsToHwRegister(unsigned long* ptr, unsigned long size)

に:

void writeWordsToHwRegister(const void * ptr, unsigned long size)
于 2012-07-20T09:46:26.207 に答える