挑戰408——組成原理(4)——強制類型轉換

本來這部分內容考綱沒有明確指出來的,但是往年的試題卻是及其熱門,可以出選擇題,也可以出大題結合寄存器部分的知識考。所以這不僅僅可以看出一個人的語言功底,同時也可以看出對補碼反碼原碼等的熟悉程度。
所以,在學習這個之前最好先回顧一下之前講的內容,
挑戰408——組成原理(2)——二進制數和十六進制數
挑戰408——組成原理(3)——原碼,補碼,反碼
好了言歸正傳,我們先來看看C語言中的基本數據類型(別問我爲啥就強調C語言,你學這門課偏硬件):

基本數據類型

  1. 整型(int):即定點整數,在寄存器中一般用補碼錶示,其最高位代表符號位,一般是4個字節。具體的位數跟變異平臺有關。
  2. 無符號整數(unsigned):無符號,即不考慮數據位,二進制碼錶示的數就是其值。一般用補碼錶示。
  3. 長整型和短整型(long short):用補碼錶示,這只是位數不同罷了(一個長一個短)。
  4. 單精度浮點數和雙精度浮點數(float double):就是我們平時說的小數點會移動的小數,前面的32位,後面的是64位。

數據間的保留,當計算記過超出機器所能表示的範圍的時候,就會發生“溢出現象”。此時面臨一個問題,那麼是丟掉前面的N位還是丟掉後面的N位呢?一般我們選擇保留後面的N位,丟掉前面的N位,若丟掉後發現不能表示正確的結果,說明產生溢出,還有一種情況就是不受影響了。

十進制轉二進制(代碼)

在進入正題之前我們先介紹一下十進制跟二進制怎麼轉換(原諒我是個代碼迷,就喜歡驗證一下)。代碼奉上:

#include <iostream>
#include <cstdlib> //引入這個頭文件,使用itoa函數,因爲這是C語言中的一個古老函數
#include <string>
using namespace std;
int main() {
	char array[64];
	int number = -4321;
	/*
     *itoa函數原型:char* itoa(int value,char *string,int radix)
	 *用法:將輸入的數轉換爲相應進制的數,radix,對應的進制
	 */
	itoa(number,array,2);
	printf("integer = %d\n string = %s\n", number, array);
	return 0;
}

結果如下:
在這裏插入圖片描述
我用的是C++的環境編寫的,有人可能會問,那爲什麼不用標準的COUT來呢?其實在精準度方面,C語言的printf函數確實是比C++做的好點。不信?那就試試下面這段代碼。只是改變了一下輸出的方式:

#include <iostream>
#include <cstdlib> //引入這個頭文件,使用itoa函數,因爲這是C語言中的一個古老函數
#include <string>
using namespace std;
int main() {
	char array[64];
	int number = -4321;
	/*
     *itoa函數,原型:char* itoa(int value,char *string,int radix)
	 *用法:將輸入的數轉換爲相應進制的數,radix,對應的進制
	 */
	itoa(number,array,2);
	cout << "number = " << number << endl;
	for (int i = 0; i < 64; i++)
	{
		cout << array[i];
	}
	return 0;
}

那麼會出現什麼結果?自己去試試吧,話說到這裏。

轉換過程

同類型之間的轉換

進入正題,先看下面的一段代碼:

#include <iostream>
#include <cstdlib> 
#include <string>
using namespace std;
int main() {
	short x = -4321;
	unsigned short y = (unsigned short) x;
	printf("x = %d, y = %u\n",x,y);
}

結果如下:
在這裏插入圖片描述
我們前面說過,它們都是在寄存器中以補碼的形式存放的,所以,我們把這兩個數寫成補碼的方式(截取後16位):
在這裏插入圖片描述
我們驚奇的發現,這裏的二進制表示居然一模一樣。但是結果卻不同,原因是X的第一位解釋成了符號,而後面的才解釋成爲真值。(這裏不知道有沒有較真的人發現,-4321的補碼沒有錯,但是61215的補碼總覺得怪怪的?哈,肯定是不記得了正數的反碼 = 補碼 =原碼,負數的纔是取反後加一)。
所以,強制類型轉換實際上是位值不變,只是改變了解釋這些位的方式。

#include <iostream>
#include <cstdlib> 
#include <string>
using namespace std;
int main() {
	unsigned short x = 65535;
	short y = (short) x;
	printf("x = %d, y = %u\n",x,y);
}

同理分析這一段代碼就一目瞭然了。

不同字節類型之間的轉換

我們知道,不同類型的數據往往其佔有的字節大小不一樣,比如:
在這裏插入圖片描述

在結合上面的第一次的代碼,-4321前面的16位都是1又是爲何?不夠的數都用1來湊?顯然不對。

#include <iostream>
#include <cstdlib> 
#include <string>
using namespace std;
int main() {
	int x = 165537, u = -34991;
	short y = (short)x;
	short v = (short)u;
	printf("x = %d, y = %u\n",x,y);
	printf("u = %d, v = %u\n",u,v);
}

當數據太大,用二進制不好表示的時候我們選擇用16進制(在之前提到過),分別是0x000286a1,0x86a1,0xffff7751, 0x7751,可以看出大字節轉向小字節的轉換的規則是:低位直接賦值(賦幾位就看你的數據佔幾位,比如short佔2字節,16位,一個16進制數代表4位2進制數),高位直接截斷

那麼顯然,反過來,小字節轉向大字節那就得擴展位數了。比如:

#include <iostream>
#include <cstdlib> 
#include <string>
using namespace std;
int main() {
	short x = -4321;
	int y = x;
	unsigned short u = (unsigned short)x;
	unsigned int v = u;
	printf("x = %d, y = %u\n",x,y);
	printf("u = %d, v = %u\n",u,v);
}

輸出的數用16進製表示我就不說了,結論:從短字長到長字長的轉換,相應的位值不變,向高位補充的數爲符號位,所以-4321前面的16位都是1,因爲它符號位是負號,如果是正號,那就變成0.

這部分內容考試必考,2分選擇題左右。後面刷題的時候回再說

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章