これまで、この進行中のCプログラミングチュートリアルシリーズでは、かなりの数の概念について説明してきましたが、基本的な概念を見逃していました。それは負の数についてです。ええ、最初のチュートリアルの1つで符号付き変数と符号なし変数について簡単に触れましたが、実際には負の数がメモリにどのように格納されるかについては説明しませんでした。
まあ、それはまさにこのチュートリアルで議論されることです。それで、これ以上面倒なことはせずに、議論から始めましょう。
2の補数
メモリ内の負の数の表現の説明を始める前に、2の補数の概念を知っておくことが重要です。どちらも2進数レベルの演算です。
非常に簡単な例を見てみましょう。 10進値が15の4バイト整数「a」があるとします。次に、バイナリ形式のメモリでどのように表されるかを示します。
00000000 00000000 00000000 00001111
ここで、1の補数を計算するには、すべてのビットを反転します。したがって、15の1の補数表現は次のとおりです。
11111111 11111111 11111111 11110000
ここで、上記のバイナリ表現に1を追加すると、2の補数が得られます。
11111111 11111111 11111111 11110001
したがって、上記の表現は2の補数の15です。
さて、あなた方の何人かは、なぜ私たちが1と2の補数について議論したのか考えているに違いありませんか?答えは、負の数の2進表現が2の補数によって計算されるという事実にあります。
信じがたい?証拠は次のとおりです:
前のセクションで計算した2の補数は、16進数形式で0xFFFFFFF1として表すことができます。それでは、Cプログラムを使用してこの値が10進形式で何であるかを見てみましょう
コードは次のとおりです:
#include <stdio.h>
int main()
{
int a = 0xFFFFFFF1;
printf("a = %d", a);
return 0;
}
そして、以下が出力です:
a = -15
今それを信じますか?数値「15」から始めて、その2の補数を計算し、2の補数の値を再び10進数に変換すると、-15であることがわかりました。
次に、コードを少し調整して、printf呼び出しが変数'a'の値を読み取るようにします。
#include <stdio.h>
int main()
{
int a = 0xFFFFFFF1;
printf("a = %u", a);
return 0;
}
これが出力です:
a = 4294967281
おっと、出力が変更され、今では大きな正の値になっています。しかし、なぜこれが起こったのですか?前に見たように、0xFFFFFFF1は15の2の補数ではありませんか?
はい、0xFFFFFFF1は15の2の補数ですが、その観点から見ない場合は、通常の値(4294967281)でもあります。違いは、その読み取り方法にあります。符号付き整数として読み取られる場合(printfの%dを介して)、出力は-15として表示されますが、符号なし整数として読み取られる場合(printfの%uを介して)、出力は次のように表示されます。 4294967281。
符号付き変数(負の値と正の値の両方を処理する)の経験則として、負の数のバイナリ表現では常に左端のビットが「1」であるのに対し、正の数の場合は常に問題のビットであることに注意してください。 0.
最後に、2の補数表現を逆にして、正の対応物を取得することもできることに注意してください。例として、-15の16進表現である0xFFFFFFF1値をもう一度見てみましょう。バイナリ形式で次のように表されます:
11111111 11111111 11111111 11110001
ここで、正の対応物を取得するには、2の補数をもう一度実行します。つまり、最初に1の補数を実行します:
00000000 00000000 00000000 00001110
そして、1を追加します
00000000 00000000 00000000 00001111
これを変換すると、10進数で値15が得られます。
このチュートリアルが、負の数がメモリ内でどのように表されるかという文脈で負の数の概念を理解するのに役立つことを願っています。このチュートリアルで使用した例を試してみることをお勧めします。問題が発生した場合、または疑問や質問がある場合は、下にコメントを記入してください。