1. 程式人生 > >警惕邏輯表示式中的無符號型別運算(C語言型別轉換)

警惕邏輯表示式中的無符號型別運算(C語言型別轉換)

今天在處理邏輯表示式時遇到了類似以下程式的問題。if( strlen(tmp)-10 <0)這個條件怎麼都進不去。經過VS除錯可發現printf("%d",b-10<0);列印的結果為0。

#include<stdio.h>

#include<string.h>
int main()
{
char tmp[]="12345";
unsigned int b;
b=5;
printf("%d",b-10<0);
return 1;

}

後來終於意識到應該是C語言型別自動轉換的緣故。因為strlen函式返回的型別為size_t,即一個unsigned int。unsigned  int型別的值和int型的10相減的結果會自動轉換成unsigned型別。無符號型別的數值當然不會比0小了。

解決辦法:要麼把strlen的結果強制轉換成int,要麼語句換成if(strlen(tmp)<10)。

下面再溫習下C語言中的型別轉換知識,溫故而知新。

自動轉換遵循以下規則:

1)        若參與運算量的型別不同,則先轉換成同一型別,然後進行運算。

2)        轉換按資料長度增加的方向進行,以保證精度不降低。如int型和long型運算時,先把int量轉成long型後再進行運算。

     a.若兩種型別的位元組數不同,轉換成位元組數高的型別

b.若兩種型別的位元組數相同,且一種有符號,一種無符號,則轉換成無符號型別

3)        所有的浮點運算都是以雙精度進行的,即使僅含float單精度量運算的表示式,也要先轉換成double型,再作運算。

4)        char型和short型參與運算時,必須先轉換成int型。

5)        在賦值運算中,賦值號兩邊量的資料型別不同時,賦值號右邊量的型別將轉換為左邊量的型別。如果右邊量的資料型別長度左邊長時,將丟失一部分資料,這樣會降低精度,丟失的部分按四捨五入向前舍入。

隱式轉換 

隱式型別轉換分三種,即算術轉換、賦值轉換和輸出轉換。
1.算術轉換
進行算術運算(加、減、乘、除、取餘以及符號運算)時,不同型別數招必須轉換成同一型別的資料才能運算,算術轉換原則為:
在進行運算時,以表示式中最長型別為主,將其他型別位據均轉換成該型別,如:
(1)若運算數中有double型或float型,則其他型別資料均轉換成double型別進行運算。
(2)若運算數中最長的型別為long型.則其他型別數均轉換成long型數。
(3)若運算數中最長型別為int型,則char型也轉換成int型進行運算。算術轉換是在運算過程中自動完成的。
2.賦值轉換


進行賦值操作時,賦值運算子右邊的資料型別必須轉換成賦值號左邊的型別,若右邊的資料型別的長度大於左邊,則要進行截斷或舍入操作。
下面用一例項說明:
      char ch;
      int i,result;
      float f;
      double d;
      result=ch/i+(f*d-i);
(1)首先計算 ch/i,ch → int型,ch/i → int型。
(2)接著計算 f*d-i,由於最長型為double型,故f→double型,i→double型,f*d-i→double型。
(3)(ch/i) 和(f*d-i)進行加運算,由於f*d-i為double型,故ch/i→double型,ch/i+(f*d-i)→double型。
(4)由於result為int型,故ch/i+(f*d-i)→double→int,即進行截斷與舍入,最後取值為整型。
3.輸出轉換
在程式中將資料用printf函式以指定格式輸出時,當要輸出的鹽據型別與輸出格式不符時,便自動進行型別轉換,如一個long型資料用整型格式(%d)輸出時,則相當於將long型轉換成整型(int)資料輸出;一個字元(char)型資料用整型格式輸出時,相當於將char型轉換成int型輸出。
注意:較長型資料轉換成短型資料輸出時,其值不能超出短型資料允許的值範圍,否則轉換時將出錯。如:
      long a=80000;
      printf("%d",a);
執行結果為14464,因為int型允許的最大值為32767,80000超出此值,故結果取以32768為模的餘數,即進行如下取餘運算:
      (80000-32768)-32768=14464;
輸出的資料型別與輸出格式不符時常常發生錯誤,如:
      int d=9;
      printf("%f",d);

      float c=3.2;
      printf("%d",c);
將產生錯誤的結果。

同一句語句或表示式如果使用了多種型別的變數和常量(型別混用),C 會自動把它們轉換成同一種類型。以下是自動型別轉換的基本規則:

      1. 在表示式中,char 和 short 型別的值,無論有符號還是無符號,都會自動轉換成 int 或者 unsigned int(如果 short 的大小和 int 一樣,unsigned short 的表示範圍就大於 int,在這種情況下,unsigned short 被轉換成 unsigned int)。因為它們被轉換成表示範圍更大的型別,故而把這種轉換稱為“升級(promotion)”。

      2. 按照從高到低的順序給各種資料型別分等級,依次為:long double, double, float, unsigned long long, long long, unsigned long, long, unsigned int 和 int。這裡有一個小小的例外,如果 long 和 int 大小相同,則 unsigned int 的等級應位於 long 之上。char 和 short 並沒有出現於這個等級列表,是因為它們應該已經被升級成了 int 或者 unsigned int。

      3. 在任何涉及兩種資料型別的操作中,它們之間等級較低的型別會被轉換成等級較高的型別。

      4. 在賦值語句中,= 右邊的值在賦予 = 左邊的變數之前,首先要將右邊的值的資料型別轉換成左邊變數的型別。也就是說,左邊變數是什麼資料型別,右邊的值就要轉換成什麼資料型別的值。這個過程可能導致右邊的值的型別升級,也可能導致其型別降級(demotion)。所謂“降級”,是指等級較高的型別被轉換成等級較低的型別。

      5. 作為引數傳遞給函式時,char 和 short 會被轉換成 int,float 會被轉換成 double。使用函式原型可以避免這種自動升級。

知識來源:http://www.cnblogs.com/hoys/archive/2012/04/09/2438718.html