2の補数を取る必要があります
x = -x;
xが符号付きか符号なしかに関係なく機能します
なんで?なぜなら、あなたがしていることは、本質的に、数値を2の補数に変換する簡単な方法だからです。
2進数を2の補数に手動で変換するショートカットは、最下位ビット(LSB)から開始し、最初の1に達するまですべてのゼロ(LSBから最上位ビットに向かって)をコピーすることです。次に、その1をコピーし、残りのすべてのビットを反転します
https://en.wikipedia.org/wiki/Two%27s_complement#Working_from_LSB_towards_MSB
設定されているビットは1つだけなので、すべてのゼロビットをコピーして残りのゼロビットを反転すると、2の補数が得られます。あなたはあなたの例でそれを見ることができます:00001000 = 8, 11111000 = -8
。他のいくつかの例:
00010000 = 16, 11110000 = -16
00100000 = 32, 11100000 = -32
01000000 = 64, 11000000 = -64
xが符号付きタイプの場合、理解しやすいです。符号なしタイプの場合、明らかに負の値はないため、C標準が符号なし操作を定義した方法に基づいて機能します。
結果の符号なし整数型で表現できない結果は、結果の型で表現できる最大値より1大きい数を法として減少するため、符号なしオペランドを含む計算はオーバーフローすることはありません。
これは、2の補数の別の定義です。これは、結果の型(つまり、この場合)で表すことができる最大値よりも大きい値が2Nであるためです。符号なしの値を否定すると、符号付きの型が符号の大きさまたは1の補数である場合でも、常にCで2の補数が生成されます。UINTN_MAX + 1
もちろん、x = -(int32_t)x;
もっと入力したい場合は、署名付きタイプにキャストすることもできます。別の解決策もあります
x = ~x + 1; // by 2's complement definition
わかりやすいソリューション_
while (!(x & 0x80000000))
x |= x << 1;
このコードは、上記のソリューションの多くの場合、常に32回ループする必要はありません。