短い答え
あなたの i
変換される UINT_MAX + 1
を追加して符号なし整数に の場合、加算は符号なしの値で実行され、大きな result
になります。 (u
の値に応じて と i
).
長文
C99 標準によると:
あなたの場合、unsigned int (u
) が 1 つあります。 ) および signed int (i
)。上記 (3) を参照すると、両方のオペランドが同じランクであるため、 i
変換する必要があります 符号なし整数に変換します。
ここで、上記の (2) を参照する必要があります。あなたの i
UINT_MAX + 1
を追加することにより、符号なしの値に変換されます .したがって、結果はUINT_MAX
の方法によって異なります 実装で定義されています。サイズは大きくなりますが、オーバーフローすることはありません。理由は次のとおりです:
ボーナス:算術変換セミ WTF
#include <stdio.h>
int main(void)
{
unsigned int plus_one = 1;
int minus_one = -1;
if(plus_one < minus_one)
printf("1 < -1");
else
printf("boring");
return 0;
}
このリンクを使用してオンラインで試すことができます:https://repl.it/repls/QuickWhimsicalBytes
ボーナス:算術変換の副作用
算術変換規則を使用して、UINT_MAX
の値を取得できます 符号なしの値を -1
に初期化する 、つまり:
unsigned int umax = -1; // umax set to UINT_MAX
上記の変換規則により、システムの符号付き数値表現に関係なく、これは移植可能であることが保証されています。詳細については、この SO の質問を参照してください:Is it safe to use -1 to set all bits to true?
署名付きから署名なしへの変換はできません 必然的に、署名された値の表現をコピーまたは再解釈するだけです。 C 標準 (C99 6.3.1.3) の引用:
最近ほぼ普遍的な 2 の補数表現の場合、ルールはビットの再解釈に対応します。ただし、他の表現 (符号と大きさまたは 1 の補数) の場合、C の実装では同じ結果が得られるように調整する必要があります。つまり、変換でビットをコピーすることはできません。たとえば、表現に関係なく、(unsigned)-1 ==UINT_MAX です。
一般に、C での変換は、表現ではなく値を操作するように定義されています。
元の質問に答えるには:
unsigned int u = 1234;
int i = -5678;
unsigned int result = u + i;
i の値は unsigned int に変換され、UINT_MAX + 1 - 5678
になります。 .この値は、符号なしの値 1234 に加算され、UINT_MAX + 1 - 4444
になります。 .
(符号なしオーバーフローとは異なり、符号付きオーバーフローは未定義の動作を引き起こします。ラップアラウンドは一般的ですが、C 標準では保証されていません。また、コンパイラの最適化によって、不当な仮定を行うコードが混乱する可能性があります。)
聖書を参照:
- 加算演算により、int が unsigned int に変換されます。
- 2 の補数表現と同じサイズの型を想定すると、ビット パターンは変わりません。
- unsigned int から signed int への変換は実装に依存します。 (しかし、最近のほとんどのプラットフォームでは、おそらく期待どおりに機能します。)
- 異なるサイズの符号付きと符号なしを組み合わせる場合、ルールはもう少し複雑になります。