このコードの結果が にならないのはなぜy == 0x100
ですか?
uint8_t x = 0xff;
unsigned y = ++((unsigned)x);
こちらでご確認ください: http://codepad.org/dmsmrtsg
このコードの結果が にならないのはなぜy == 0x100
ですか?
uint8_t x = 0xff;
unsigned y = ++((unsigned)x);
こちらでご確認ください: http://codepad.org/dmsmrtsg
あなたが投稿したコードは、C 言語の観点からは無効です。C でのキャストの結果は右辺値です。の引数としては使用できません++
。演算子++
には左辺値引数が必要です。つまり、式++((unsigned) x)
は標準 C 言語ではコンパイルできません。
この場合に実際に観察されるのは、GCC の「一般化された左辺値」拡張です。
http://gcc.gnu.org/onlinedocs/gcc-3.4.4/gcc/Lvalues.html
その拡張に従って (標準 C とは逆に)、左辺値に適用されたキャストは左辺値を生成します。結果の「一般化された」左辺値に何かを書き込もうとすると、書き込まれる値が2 回変換されます。最初に明示的なキャストによって指定された型に変換され、次に中間結果が受信者オブジェクトの型に再度変換されます。最終結果は受信者オブジェクトに配置されます。
たとえば、あなたのx
場合
(unsigned) x = 0x100;
実際にはGCCによって次のように解釈されます
x = (uint8_t) (unsigned) 0x100;
の最終値はx
になります0
。
そして、これはまさにあなたの例で起こっていることです。GCC では、
++((unsigned) x)
と同等です
(unsigned) x = (unsigned) x + 1;
これは、GCC によって次のように解釈されます。
x = (uint8_t) (unsigned) ((unsigned) x + 1);
これが結果として入る理由であり、0
それが に割り当てられます。x
0
y
この拡張機能は、GCC のドキュメントでは非推奨と呼ばれています。
これを開始するには、有効なCコードではありません。どのようにコンパイルしたかわかりませんが、リンクには出力が表示されるので、この1つの主要な仮定に基づいて何が起こっているのかを説明します。
この行unsigned y = ++((unsigned x));
では、2番目の行unsigned
がコンパイラーによって削除されていると思います。したがって、ビルドできるのはなぜですか。
だから、それを仮定すると...
uint8_t x = 0xff; // 8 bit value, max is 255(10) or 0xFF(16)
unsigned y = ++((unsigned)x);
x
これで、そのタイプの最大値がすでに設定されています。++
を介して+1すると、y
の値が得られない理由を知りたいと思います0x100
。
x
は8ビットであり、型キャストしても8ビットであるという事実は変わりません。だから私たちが言うとき:
++x
インクリメントしていますx
(x=x+1
)。したがって、符号なしの8ビット値が最大であり、それに1を追加すると、0にラップアラウンドされます。したがって、0y
になります。
これを機能させたい場合は、次のようにすることができます。
int main(void)
{
unsigned char x = 0xFF; //I'm using char because it's 8 bit too
unsigned int y = 1+x; //no need to typecast, we're already unsigned
printf("%#x %#x\n", x, y);
return 0;
}
x==0xFF
これで、期待値(およびy==0x100
)を取得できます。
これを試して:
uint8_t x = 0xff;
unsigned y = ((unsigned)x) + 1;
(unsigned) x
は2バイトの値になっているため、期待どおりに出力されます0x0100
。
今これを試してみてください:
uint8_t x = 0xff;
++x;
の値はに0xff
ラップアラウンドし0x00
ます。
私はあなたの抜粋にいくつかの小さな透明性コードを入れました.それはすべてを説明しています.
#include <stdio.h>
#include <stdint.h> // not needed
int main(void) {
uint8_t x = 0xff;
printf("%d\n", sizeof(x));
unsigned y = ++((unsigned)x);
printf("%d\n", sizeof(y));
printf("0x%x\n", y);
printf("%d\n", sizeof(y));
return 0;
}
そして出力は
1 // size of x
4 // size of y before computation
0x100 // computed value of y from your code
4 // size of y after computation
最初に注意すべきことは、sizeof(y)
が計算全体で一定に保たれることです。
アウトプットから、
uint8_t
= 1 バイトunsigned
= 4 バイトrealloc
C でキャストを行うときは、 「ブロックから持っているこのデータを取得し、メモリ内のサイズをキャストしたいサイズに増やして (または減らして)、次に返す」という暗黙の呼び出しと考えてください。新しいブロックの同じデータ。
そして、私たちのサイズunsigned
から、1 バイト操作からの計算結果に適合する十分なスペースがあります。
コードをバイトレベルの詳細で再説明すると、
x = 11111111 = 0xff (in a byte)
(unsigned)x = 00000000000000000000000011111111 = 0xff (in a word)
++((unsigned)x) = 00000000000000000000000100000000 = 0x100