2011-11-15 17 views
0

ネイティブのunsigned long変数を、その内部に2つのunsigned short変数を含むバッファーとして使用しています。私のC++の知識から、有効な方法でなければなりません。私はこのメソッドを使用して、2つのunsigned charを1つのunsigned shortの中に何も問題なく格納します。残念なことに、それを別のアーキテクチャで使用すると、それは不思議に反応します。 2回目の割り当て後に値が更新されたようです。 (オーバーフロー)ケースはそれを実証するだけのものです。誰かがそれがなぜそのように反応するのかについていくつかの光を当てることができますか?型キャスト後の値の影響がありません

unsigned long dwTest = 0xFFEEDDCC; 

printf("sizeof(unsigned short) = %d\n", sizeof(unsigned short)); 
printf("dwTest = %08X\n", dwTest); 

//Address + values 
printf("Addresses + Values: %08X <- %08X, %08X <- %08X\n", (DWORD)(&((unsigned short*)&dwTest)[0]), (((unsigned short*)&dwTest)[0]), (DWORD)(&((unsigned short*)&dwTest)[1]), (((unsigned short*)&dwTest)[1])); 

((unsigned short*)&dwTest)[0] = (WORD)0xAAAA; 
printf("dwTest = %08X\n", dwTest); 

((unsigned short*)&dwTest)[1] = (WORD)0xBBBB; 
printf("dwTest = %08X\n", dwTest); 

//(Overflow) 
((unsigned short*)&dwTest)[2] = (WORD)0x9999; 

printf("dwTest = %08X\n", dwTest); 

のVisual C++ 2010の出力(OK):

sizeof(unsigned short) = 2 
dwTest = FFEEDDCC 
Addresses + Values: 0031F728 <- 0000DDCC, 0031F72A <- 0000FFEE 

dwTest = FFEEAAAA 

dwTest = BBBBAAAA 

dwTest = BBBBAAAA 

はARM9 GCC Crosstool出力(動作しない):

sizeof(unsigned short) = 2 
dwTest = FFEEDDCC 
Addresses + Values: 7FAFECD8 <- 0000DDCC, 7FAFECDA <- 0000FFEE 

dwTest = FFEEDDCC 

dwTest = FFEEAAAA 

dwTest = BBBBAAAA 
+0

警告を有効にして( '-Wall')コンパイルし、警告を見てください。それでは、ここでSOの "厳密なエイリアシング"(ソリューション:ユニオンを使用)を見てください。 – ninjalj

答えて

2

何をしようとするが呼ばれるタイプ - 懲罰これを行うには2つの伝統的な方法があります。

これを行う方法は、ポインタ(あなたが行ったこと)を介してです。残念ながら、これはオプティマイザと競合します。停止問題のために、オプティマイザは、一般的なケースでは、2つのポインタがお互いにエイリアスしていないことを知ることができません。これは、ポインタを介して変更された可能性のある値をコンパイラが再ロードしなければならないことを意味します。

したがって、厳密なエイリアシングルールが導入されました。基本的には、2つのポインタが同じ型であるときに、2つのポインタがお互いをエイリアスできるだけです。特別な規則として、char *は、他のポインタのエイリアスを付けることができます(ただし、その逆はありません)。 これにより、ポインターを介して型打ちが中断され、コンパイラーはより効率的なコードを生成することができます。 gccは、タイプpunningを検出し、警告が有効になっているとき、それはこのように警告を表示します:タイプpunningを行うには

warning: dereferencing type-punned pointer will break strict-aliasing rules 

もう一つの方法は、労働組合を経由する:

union { 
    int i; 
    short s[2]; 
} u; 
u.i = 0xDEADBEEF; 
u.s[0] = 0xBABE; 
.... 

これは新しい全体をすることができます開きますワームの最良の場合、これは実装に依存します。今、私はC89標準へのアクセス権を持っていませんが、C99では、最初に格納された最後のもの以外の組合員の値が指定されていないと述べました。これはTCで変更され、最後に格納されたメンバーに対応しないバイトの値が指定されておらず、最後に格納されたメンバーに対応するバイトが新しい型(明らかに実装に依存するもの)。

C++では、標準の組込みハックに関する言語を見つけることができません。とにかく、C++にはreinterpret_cast<>があります。これは、C++での型打ちに使用する必要があります(reinterpret_cast<>の参照バリアントを使用してください)。

とにかく、タイプ・パニング(インプリメンテーション依存)を使用しないでください。ビット・シフトを使用して値を手動で構築する必要があります。

+0

明確な回答をいただきありがとうございます – Dunge

関連する問題