天天看點

C語言:資料類型轉換 自動轉換 強制轉換

資料類型轉換就是将資料(變量、數值、表達式的結果等)從一種類型轉換為另一種類型。

自動類型轉換就是編譯器默默地、隐式地、偷偷地進行的資料類型轉換,這種轉換不需要程式員幹預,會自動發生。

1) 将一種類型的資料指派給另外一種類型的變量時就會發生自動類型轉換,例如:

float f = 100;

100 是 int 類型的資料,需要先轉換為 float 類型才能指派給變量 f。再如:

int n = f;

f 是 float 類型的資料,需要先轉換為 int 類型才能指派給變量 n。

在指派運算中,指派号兩邊的資料類型不同時,需要把右邊表達式的類型轉換為左邊變量的類型,這可能會導緻資料失真,或者精度降低;是以說,自動類型轉換并不一定是安全的。對于不安全的類型轉換,編譯器一般會給出警告。

2) 在不同類型的混合運算中,編譯器也會自動地轉換資料類型,将參與運算的所有資料先轉換為同一種類型,然後再進行計算。轉換的規則如下:

轉換按資料長度增加的方向進行,以保證數值不失真,或者精度不降低。例如,int 和 long 參與運算時,先把 int 類型的資料轉成 long 類型後再進行運算。

所有的浮點運算都是以雙精度進行的,即使運算中隻有 float 類型,也要先轉換為 double 類型,才能進行運算。

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

下圖對這種轉換規則進行了更加形象地描述:

C語言:資料類型轉換 自動轉換 強制轉換
unsigned 也即 unsigned int,此時可以省略 int,隻寫 unsigned。

自動類型轉換示例:

#include<stdio.h>

int main(){

float PI = 3.14159;

int s1, r = 5;

double s2;

s1 = r * r * PI;

s2 = r * r * PI;

printf("s1=%d, s2=%f\n", s1, s2);

return 0;

}

運作結果:

s1=78, s2=78.539749

在計算表達式<code>r*r*PI</code>時,r 和 PI 都被轉換成 double 類型,表達式的結果也是 double 類型。但由于 s1 為整型,是以指派運算的結果仍為整型,舍去了小數部分,導緻資料失真。

自動類型轉換是編譯器根據代碼的上下文環境自行判斷的結果,有時候并不是那麼“智能”,不能滿足所有的需求。如果需要,程式員也可以自己在代碼中明确地提出要進行類型轉換,這稱為強制類型轉換。

自動類型轉換是編譯器默默地、隐式地進行的一種類型轉換,不需要在代碼中展現出來;強制類型轉換是程式員明确提出的、需要通過特定格式的代碼來指明的一種類型轉換。換句話說,自動類型轉換不需要程式員幹預,強制類型轉換必須有程式員幹預。

強制類型轉換的格式為:

<code>type_name</code>為新類型名稱,<code>expression</code>為表達式。例如:

(float) a; //将變量 a 轉換為 float 類型

(int)(x+y); //把表達式 x+y 的結果轉換為 int 整型

(float) 100; //将數值 100(預設為int類型)轉換為 float 類型

下面是一個需要強制類型轉換的經典例子:

#include &lt;stdio.h&gt;

int sum = 103; //總數

int count = 7; //數目

double average; //平均數

average = (double) sum / count;

printf("Average is %lf!\n", average);

Average is 14.714286!

sum 和 count 都是 int 類型,如果不進行幹預,那麼<code>sum / count</code>的運算結果也是 int 類型,小數部分将被丢棄;雖然是 average 是 double 類型,可以接收小數部分,但是心有餘力不足,小數部分提前就被“閹割”了,它隻能接收到整數部分,這就導緻除法運算的結果嚴重失真。

既然 average 是 double 類型,為何不充分利用,盡量提高運算結果的精度呢?為了達到這個目标,我們隻要将 sum 或者 count 其中之一轉換為 double 類型即可。上面的代碼中,我們将 sum 強制轉換為 double 類型,這樣<code>sum / count</code>的結果也将變成 double 類型,就可以保留小數部分了,average 接收到的值也會更加精确。

在這段代碼中,有兩點需要注意:

對于除法運算,如果除數和被除數都是整數,那麼運算結果也是整數,小數部分将被直接丢棄;如果除數和被除數其中有一個是小數,那麼運算結果也是小數。這一點已在《C語言加減乘除運算》中進行了詳細說明。

<code>( )</code>的優先級高于<code>/</code>,對于表達式<code>(double) sum / count</code>,會先執行<code>(double) sum</code>,将 sum 轉換為 double 類型,然後再進行除法運算,這樣運算結果也是 double 類型,能夠保留小數部分。注意不要寫作<code>(double) (sum / count)</code>,這樣寫運算結果将是 3.000000,仍然不能保留小數部分。

無論是自動類型轉換還是強制類型轉換,都隻是為了本次運算而進行的臨時性轉換,轉換的結果也會儲存到臨時的記憶體空間,不會改變資料本來的類型或者值。請看下面的例子:

double total = 400.8; //總價

int count = 5; //數目

double unit; //單價

int total_int = (int)total;

unit = total / count;

printf("total=%lf, total_int=%d, unit=%lf\n", total, total_int, unit);

total=400.800000, total_int=400, unit=80.160000

注意看第 6 行代碼,total 變量被轉換成了 int 類型才指派給 total_int 變量,而這種轉換并未影響 total 變量本身的類型和值。如果 total 的值變了,那麼 total 的輸出結果将變為 400.000000;如果 total 的類型變了,那麼 unit 的輸出結果将變為 80.000000。

在C語言中,有些類型既可以自動轉換,也可以強制轉換,例如 int 到 double,float 到 int 等;而有些類型隻能強制轉換,不能自動轉換,例如以後将要學到的 void * 到 int *,int 到 char * 等。

可以自動轉換的類型一定能夠強制轉換,但是,需要強制轉換的類型不一定能夠自動轉換。現在我們學到的資料類型,既可以自動轉換,又可以強制轉換,以後我們還會學到一些隻能強制轉換而不能自動轉換的類型。

可以自動進行的類型轉換一般風險較低,不會對程式帶來嚴重的後果,例如,int 到 double 沒有什麼缺點,float 到 int 頂多是數值失真。隻能強制進行的類型轉換一般風險較高,或者行為匪夷所思,例如,char * 到 int * 就是很奇怪的一種轉換,這會導緻取得的值也很奇怪,再如,int 到 char * 就是風險極高的一種轉換,一般會導緻程式崩潰。

使用強制類型轉換時,程式員自己要意識到潛在的風險。