混合運算中不同數據類型之間的隱式轉換原則(C語言)


C語言的數據類型

c語言中,有關數據類型的分類,網上有很多種版本,未找到比較統一的標准,下圖為我比較認可的划分:

常量的默認類型

在C語言中,數值常量分為兩種:整數和小數。整數常量默認為有符號的 int 類型,而小數常量默認為 double 類型。字符常量被認為是一種特殊的整型常量,默認類型為有符號的 char ,而字符串常量一般被認為 const char 類型。需要注意的是,不同的編譯器可能略有不同,但一般遵守該規則。

隱式轉換

C語言在以下四種情況中會進行隱式轉換:
(1)算術運算式中,類型能夠換為類型。

    所謂高低,是指表示的范圍大小。通常和內存默認分配的存儲空間大小及有無符號位有關。

(2)賦值表達式中,右邊表達式的值自動隱式換為左邊變量的類型,並賦值給它。
(3)函數調用中參數傳遞時,系統隱式地將實參轉換為形參的類型后,賦給形參。
(4)函數有返回值時,系統將隱式地將返回表達式類型換為返回值類型,賦值給調用函數。

算數運算中的轉換規則

算數運算中,有如下類型轉換規則:

(1)字符必須先轉換為整數(C語言規定字符類型數據和整型數據之間可以通用) 。
(2) short 型換為 int 型(同屬於整型) 。
(3) float 型數據在運算時一律換為雙精度 double 型,以提高運算精度(同屬於實型,即浮點型) 。

總的來說,當不同類型的數據進行操作時,應當首先將其轉換成相同的數據類型,然后進行操作,轉換規則是由低級向高級轉換(如上圖所示)。

算術運算示例

執行: x = 100 + 'a' + 1.5 * u + f / 'b' - s * 3.1415926 

其中,u為 unsigned 型,f為 float 型,s為 short 型,x為 float 型。式中右面表達式按如下步驟處理:

  1. 首先將'a'、'b'和s換成 int ,將1.5和f轉換為 double 型。
  2. 計算100+'a',因'a'已轉換為 int 型,於是此運算結果為197。
  3. 計算1.5*u,由於1.5已轉換為 double ,u是 unsigned 型,於是首先u轉換為 double ,然后進行運算,運算結果為 double 。
  4. 計算197+1.5 * u,先將197轉換為 double (如197.00…00),其結果為 double 。
  5. 計算f/ 'b',f已轉換為 double ,'b'已轉換為 int ,於是先將'b'再轉換為 double ,其結果為 double 。
  6. 計算(197+1.5 * u)+f / 'b',者均為 double ,於是結果也為 double 。
  7. 計算s * 3.1415926,先將s由int轉換為 double ,然后進行運算,其結果為 double 。
  8. 之后與前面得的結果相減,結果為 double 。
  9. 最后將表達式的結果轉換為 float 並賦給x。

有符號數與無符號數之間運算問題

當表達式中存在有符號類型和無符號類型時,所有的操作數都自動轉換為無符號類型。因此,從這個意義上講,無符號數的運算優先級要高於有符號數,這一點對於應當頻繁用到無符號數據類型的嵌入式系統來說是豐常重要的。 

首先進行一個實驗,分別定義一個 signed int 型數據和 unsigned int 型數據,然后進行大小比較:

unsigned int a = 20;
signed int b = -130;

實驗證明:$b > a$,也就是說$-130 > 20$,為什么會出現這樣的結果呢?

這是因為在C語言操作中,如果遇到無符號數與有符號數之間的操作,編譯器會自動轉化為無符號數來進行處理,因此$a=20, b=4294967166$,這樣比較下去當然$b > a$了。再舉一個例子:

 unsigned int a = 20;
 signed int b = -130;
 std::cout << a + b << std::endl;

結果輸出為$4294967186$。同樣的道理:在運算之前,$a=20$,$b$被轉化為$4294967166$,所以$a+b=42949671864,減法和乘法的運算結果類似。

如果作為 signed int 型數據的b=-130,b與立即數之間操作時不影響b的類型,運算結果仍然為 signed int 型:

signed int b = -130;
std::cout << b + 30 << std::endl;
// 輸出為-100

而對於浮點數來說,浮點數 float, double 實際上都是有符號數, unsigned 和 signed 前綴不能加在 float 和 double 之上,當然就不存在有符號數根無符號數之間轉化的問題了。

 示例

#include <iostream>
/*
當表達式中存在符號類型和無符號類型時
所有的操作數都自動轉換為無符號類型
*/
using namespace std;
char getChar(int x,int y){
    char c;
    unsigned int a = x;
    unsigned int b = a + y;
    (a + y > 10)?(c = 1):(c = 2);
    return c;
}
void main(){
char c1 = getChar(7,4);
char c2 = getChar(7,3);
char c3 = getChar(7,-7);
char c4 = getChar(7,-8);
 
printf("c1=%d\n",c1);
printf("c2=%d\n",c2);
printf("c3=%d\n",c3);
printf("c4=%d\n",c4);
system("pause");
}
// 輸出: c1=1  c2=2  c3=2  c4=1

規則總結

1、所有比  int 型小的數據類型,包括  char, signed char, unsigned char, short, signed short, unsigned short 轉換為  int 型。如果轉換后的數據會超出  int 型所能表示的范圍的話,則轉換為  unsigned int 型;
2、  bool 型轉化為  int 型時,  false 轉化為0,  true 轉換為1;反過來所有的整數類型轉化為  bool 時,0轉化為  false ,其它非零值都轉為  true ;
3、如果表達式中混有  unsigned short 和  int 型時,如果  int 型數據可以表示所有的  unsigned short 型的話,則將  unsigned short 類型的數據轉換為  int 型,否則,  unsigned short 類型及  int 型都轉換為  unsigned int 類型。舉個例子,在32位機上,int是32位,范圍$-2,147,483,648 to 2,147,483,647$,  unsigned short 是16位,范圍$0 to 65,535$,這樣  int 型的足夠表示  unsigned short 類型的數據,因此在混有這兩者的運算中,  unsigned short 類型數據被轉換為  int 型;
4、 unsigned int 與  long 類型的轉換規則同3,在32位機上,  unsigned int 是32位,范圍$0 to 4,294,967,295$,  long 是32位,范圍$-2,147,483,648 to 2,147,483,647$,可見  long 類型不夠表示所有的  unsigned int 型,因此在混有  unsigned int 及  long 的表達式中,兩者都被轉換為  unsigned long ;
5、如果表達式中既有  int 又有  unsigned int ,則所有的  int 數據都被轉化為  unsigned int 類型。

范例解析

unsigned int i = 3;
cout << i * -1;
// 輸出?

各數據類型的表示范圍

來自MSDN

補充說明:

1)在32位機上,  int 型和  unsigned int 型都是32位(4個字節)。
2)  enum 會跟據最大值來決定類型,一般來說為  int 型,如果超出  int 型所能表示的范圍,則用比  int 型大的最小類型來表示(  unsigned int, long 或者  unsigned long )。
3)關於類型的大小。一般用所能表示的數據范圍來比較類型的大小,如  char 型<  unsigned char 型<  short 型...在表達式中,一般都是由小的類型向大的類型轉換(強制類型轉換除外)。

答案

輸出是$4294967293$。
原因:在表達式$i * -1$中,$i$是  unsigned int 型,$-1$是  int 型(常量整數的類型同  enum ),按規則總結第5條可以知道$-1$必須轉換為  unsigned int 型,即十六進制的0xFFFFFFFF,十進制的$4294967295$,然后再與$i$相乘,即$44294967295 * 3$,如果不考慮溢出的話,結果是$12884901885$,十六進制$0x2FFFFFFFD$,由於  unsigned int 只能表示32位,因此結果是0xFFFFFFFD,即十進制的$4294967293$。

(整理自網絡)

參考資料:

https://blog.csdn.net/zhuimengzh/article/details/6728492

https://blog.csdn.net/miaouu/article/details/5213042


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM