為啥-1大於1,-1乘3卻不等於-3?直到了解C語言自動轉換原則後...

Hsuesh發表於2020-12-04

今天我們由C語言的一個經典題目入手,跟大家聊聊C語言一個非常重要的規則,不要著急,讓我們從-1大於1的例子說起。

unsigned int i=1;

signed int j=-1;

很簡單,無符號數i,有符號數j,比較i和j的大小,按照常理i是大於j的,但是實驗證明j>i,也就是說-1>1,為什麼會這樣呢?

其實出現這個情況的原因就是C語言中的自動轉換原則,這也是今天我們想給大家說的話題。在C語言中,若遇到無符號數和有符號數之間的操作,這時候會出現資料型別的提升現象,編譯器會自動把有符號數轉化為無符號數來進行處理,因此i是1沒錯,但j卻不是-1了,而是變成了 4294967295。所以j>i了。

 

關於資料為何是4294967295,我們今天從數學的角度給大家分析一下,供大家參考。

首先大家知道無符號數unsigned int的表示範圍是:[0 4294967295 ]= [0 2147483647] U [2147483648 4294967295],數學上稱為值域。而有符號數int的值域是 [-2147483648—2147483647]。兩個區間的元素個數都是4294967296個。

由此看出,二者的公共域是[0 2147483647],所以有符號數int的[-2147483648 -1] 對應 unsigned int的[2147483648 4294967295],這種一一對應的關係,數學上叫做對映。到這裡,資料的對應關係就一目瞭然了, -1 自然對應的就是 4294967295了。

由-1大於1的例子,我們對C語言的自動轉換原則進行簡單總結。

一般來說,C語言存在4種情況的自動轉換,也稱為隱式轉換。

1、算術運算式中,低階型別轉換為高階型別。(下面的圖對低階和高階進行了說明,大家可以參考)

 

2、賦值表示式中,右邊表示式的值自動隱式轉換為左邊變數的型別,並賦值給他。

3、函式呼叫中引數傳遞時,系統隱式地將實參轉換為形參的型別後,賦給形參。

4、函式有返回值時,系統將隱式地將返回表示式型別轉換為返回值型別,賦值給呼叫函式。

當然,以上情況只是進行了一般的總結,有些細節還沒有提到,比如字元必須先轉換為整數,short必須轉換為int,float型資料在運算時必須轉換為double來提高運算精度等等,有興趣的可以自行去了解學習。

瞭解自動轉換原則後,我們再來看這個微軟面試題

#include<iostream>

using namespace std;

int main(void)

{

  unsigned int i=3;

  cout<<i * -1;

  return 0;

}

問結果會輸出什麼?有人說不是3而應該是12884901885,因為發生了隱式轉換。其實本題的答案是4294967293,哪裡有問題呢?我們一步一步分析,有符號數-1與無符號數3進行算數運算,-1變為無符號數4294967295,再乘3得12884901885。到這裡都沒問題,但是有一點很多人忽略了:那就是無符號數unsigned int只能表示32位,而此時的結果發生了溢位!因此結果是4294967293。

最後,關於本題這裡有一點,因為上述程式碼是C++,大家可以改寫成C語言,用printf來輸出,再看看執行結果,你會有新的發現哦!

好啦,就寫到這裡吧,希望今天的文章對大家的學習有所幫助。

 

最後,如果你也想成為程式設計師,想要快速掌握程式設計,趕緊加入學習企鵝圈子!

裡面有資深專業軟體開發工程師,線上解答你的所有疑惑~程式語言入門“so easy”

程式設計學習書籍:

 

程式設計學習視訊:

 

相關文章