[C++] 位元運算子(NOT)與 2 補數

Martin
4 min readAug 26, 2018

說位元運算子有哪些,大家一定都聽過 AND、OR、XOR、NOT

Table 1

如果不想看我理解的過程可以直接下拉到分隔線後XD

而我今天想介紹的是 NOT,因為前些日子在重頭複習 C++
在介紹運算子的章節對於這個 NOT 有點不太理解
只知道他是反向,把 1 變 0、0 變 1。

有個練習題目是這樣:

#include <iostream>using namespace std;int main()
{
int a = 1;
cout << "~a= " << ~a << endl;
}

印出來的結果是 ~a = -2
Why!? 好,我們把它轉成二進制來看這過程:
int a = 1; => 0000 0000 0000 0001

~a 就是把 1 變 0、 0 變 1
~a = 1111 1111 1111 1110

這步驟沒有問題
但是 1111 1111 1111 1110 轉成十進制是 65534 才對啊
怎麼會是 -2 呢?

這時候 Google 是我們的好朋友
找到都會提到 1 的補數和 2 的補數
但不太懂它的過程,什麼時候1的補數、什麼時候2的補數!?

趕緊到Line 群組問了朋友
回答差不多就是:

[ 取 2 的補數阿 ]
或是
[ 先取 1 的補數再加 1 ]
或是
[ 反向就是1的補數]
接著貼出補數的wiki 的文章
然後又跑出有還有正負號
當時花了一段時間,感覺好像懂了

直到前天吃完中餐在看 Bitwise operation
看到了這個範例

#include <iostream>using namespace std;int main()
{
char a = 255;
cout << "~a= " << ~a << endl;
}

印出來的結果是 ~a = 0

Why!?
找了張紙紀錄一下,先把 255 轉成二進制

char a = 255 => 1111 1111

~a => 0000 0000

腦裡浮現朋友說的話,[反向就是取 2 的補數]
所以先對 1111 1111 取 1 的補數再加 1
0000 0000 (1的補數) + 1 => 0000 0001

不對阿,這樣根本不是 0 阿
放棄午休時間,仔細研究了一番
總算了解整個過程

==== 分隔線 =====================

以下是我自己理解後歸納出它的整個過程

首先針對第一個題目

int a = 1;

我們先把 a 轉成二進制看

int a = 1 => 0000 0000 0000 0001

接著把它反向

~a = 1111 1111 1111 1110

注意,這時候這個值就是答案了
只是電腦它會用 2 的補數來表示這個值
所以 cout 出來的值就會是把 1111 1111 1111 1110 取 2 的補數後的值

那我們就來看會取 2 的補數後的值是多少

Step 1. 先把 1111 1111 1111 1110 取 1 的補數

1111 1111 1111 1110 => 0000 0000 0000 0001 (1的補數)

Step 2. 接著 2 的補數就是 1 的補數再加 1

0000 0000 0000 0001 + 1 => 0000 0000 0000 0010(2的補數)

這樣是 2 耶,怎麼不是 -2
沒錯,2 不是正確答案,我們還要考慮到正負號

對電腦來說,它只知道 0 和 1
卻不知道正負,所以它會用 MSB (最左邊/高的位元) 的數字來判斷正負
1:正數, 0:負數

我們再回到 a 反向後的值
'1'111 1111 1111 1110 => MSB =1, 代表負號

接著照著上面的 Step 1 和 Step 2 ,最後出來就會是 - 2

挖,好像真的是這樣耶
我們再拿第2個題目試試看

char a = 255

一樣轉成二進制 1111 1111

然後反向
~ a = > '0'000 0000

這邊有注意到 MSB 是 0 嗎?
代表這個值是正的。

Step 1. 取 1 的補數

0000 0000 => 1111 1111 (1 的補數)

Step 2. 1的補數再加 1

1111 1111(1的補數)+ 1 => '1' 0000 0000 (2的補數)

這題答案是 0
可是2 的補數進位後最左邊不是有個 '1' 嗎?
沒錯,它進位了
但是 a 宣告的型別是 char
char 只佔了記憶體空間 1 個 byte (8 個 bits)
也就是說 char 最大的值只能到 1111 1111
再加 1 就會造成溢位,所以就只看後面的 8 個 bits 0000 0000
所以 ~a 印出來的結果就會是 0

以上是我對 NOT 與 二補數的理解
不知道是否有地方說明不正確或不清楚
非常歡迎給予指正~

--

--