1. 程式人生 > >11-有符號數和無符號數

11-有符號數和無符號數

1. 有符號數和無符號數

無符號數,因為沒有符號位,所以只能表示一個正數。

有符號數,因為存在符號位,符號位如果是0的話,代表這是一個正數,符號位如果是1的話,代表這個數是一個負數。

 

我們可以用db偽指令來宣告一些數字:

 

編譯之後:

10D的十六進位制表示就是0x0A,11D的十六進位制表示就是0x0B,17D的十六進位制表示就是0x11

 

但自從學習組合語言,我們還沒有用過負數,好像組合語言裡面根本就沒有負數一樣。為此,現在有一個十進位制的負數-3d,要求轉換成1個位元組,並用十六進位制來表示。

 

修改db偽指令:

db 10,11,17,-3

 

編譯後的結果:

我們可以看到-3的十六進位制數竟然是FD,那麼這個FD到底是怎麼來的呢?

首先十進位制3的二進位制是:0000 0011,因為十進位制-3是負數,所以符號位是1,推匯出-3的原碼:1000 0011,我們需要根據原碼轉換成計算機表示的補碼(關於反碼,補碼的計算規則相信大家應該還記得吧):

-3的反碼就是:1111 1100

-3的補碼就是:1111 1101

轉換成十六進位制就是:FD

 

那麼問題來了,253D的十六進位制表示也是FD,這意味著無論是253還是-3,彙編器統統都給轉換成FD了,也就是說,FD既可以代表-3又可以代表253,那假如給你一個FD,那麼你認為它代表什麼呢?

看到上面這張圖是不是很懵逼??? 其實這個問題放在幾十年前,那時的計算機工程師面對這種情況同樣也很懵逼。

對於1111 1101這個數,你既可以理解為-3,也可以理解為253。也就是說,在計算機裡幾乎所有的指令,既能操作無符號數,又能操作有符號數,並且結果完全都正確,怎麼理解由你自己決定。

但總有例外,比如除法指令和乘法指令,div指令就只能完成無符號除法指令(Unsigned Divide),如果是完成有符號除法指令(Signed divide),就要使用idiv指令。這兩個指令的使用方法是一樣的,區別在於div是針對無符號數,而idiv是針對有符號數。

C語言同理,我們來看下面這段程式碼:

int main(void)
{
	//對於數字12在C語言中,也有無符號,有符號數兩種表示方法
	int num1 = 12;				//一般預設是有符號數,signed
	unsigned int num2 = 12;		//使用unsigned關鍵字明確指定為無符號數
	return 0;
}

因此,在組合語言中計算數字時,這個數字是有符號數還是無符號數由你自己決定,在C語言中也是同樣的道理。

 

2. 標誌暫存器

這一節我們要學習一個新的暫存器,叫做標誌暫存器。關於標誌暫存器,在16位的組合語言中,這個暫存器叫做flag。在32位的組合語言中,這個暫存器叫做eflag,即標誌暫存器EFL。

標誌暫存器EFL在計算機的作用是主要反映處理器的狀態和ALU運算結果的某些特徵

比如CF這個標誌位,翻譯過來指的是(CarryFlag),當進行無符號運算的時候,如果產生進位和借位,CF就會變成1,否則變成0。

 

來看一個示例:

;al是一個8位的暫存器,最大隻能存放1111 1111(0xFF),在這種情況下,如果再加1的話,就會產生溢位。
mov al,0xFE
inc al	
inc al	

執行第二條add指令時,暫存器ax裡的內容就會溢位,而標誌暫存器裡的CF標誌位就會置為1。

 

當把add指令換成inc指令,我們發現暫存器ax的內容溢位時,CF標誌位並沒有置1,至於原因,書上的解釋是inc指令不會影響CF標誌位。