數據類型及其占計算機中的字節大小。
不同類型數據間的混合運算與類型轉換
1.自動類型轉換
在C語言中,自動類型轉換遵循以下規則:
①若參與運算量的類型不同,則先轉換成同一類型,然后進行運算
②轉換按數據長度增加的方向進行,以保證精度不降低。如int型和long型運算時,先把int量轉成long型后再進行運算
a、若兩種類型的字節數不同,轉換成字節數高的類型
b、若兩種類型的字節數相同,且一種有符號,一種無符號,則轉換成無符號類型
③所有的浮點運算都是以雙精度進行的,即使是兩個float單精度量運算的表達式,也要先轉換成double型,再作運算.
④char型和short型參與運算時,必須先轉換成int型
⑤在賦值運算中,賦值號兩邊量的數據類型不同時,賦值號右邊量的類型將轉換為左邊量的類型。
2.強制類型轉換
強制類型轉換一般格式如下:
(類型名)(表達式)
這種強制類型轉換操作並不改變操作數本身
首先進行一個實驗,分別定義一個signed int型數據和unsigned int型數據,然后進行大小比較:
unsigned int a = 20;signed int b = -130 ;b?還是b>a?實驗證明b>a,也就是說-130>20,為什么會出現這樣的結果呢?
這是因為在C語言操作中,如果遇到無符號數與有符號數之間的操作,編譯器會自動轉化為無符號數來進行處理,因此a=20,b=4294967166,這樣比較下去當然b>a了。
unsigned int a=20; signed int b=-130;a + b結果輸出為4294967186,同樣的道理,在運算之前,a=20,b被轉化為4294967166,所以a+b=4294967186
減法和乘法的運算結果類似。 unsigned int i=3;i * -1;問結果是多少
列子
-
為什么 7.5 用%d輸出的是0?分析如下:
答:首先來了解下printf的輸出格式,int 和 long int 都是32位的(4個字節),用%d輸出;float 、double都是%f輸出,但 float 是32位的(4個字節),double 是64位的(8個字節),所以在參數傳遞的時候C語言統一將 float 類型數值傳換為 double 類型再傳入 printf 函數。如果是32位整型則輸出格式為%lld。
- 為什么float非要轉成double類型呢?
答:因為printf格式控制浮點型輸出只有%f,所以統一按doube類型輸出,不像整型有32位的%d或%ld,64位的有%lld,這就將32位整型和64位整型用不同的格式控制分開了,而%f則沒有,所以printf輸出的浮點數其實是統一遍歷了64位內存,如果float傳入printf沒有進行轉換,那么printf輸出高32位數據將不可預知,printf輸出結果也就不正確了,因此傳入printf的浮點數都會被編譯器隱含轉成double類型。
-
下面來講一下 float a=7.5f ; printf("%d",f)輸出為0的情況:
答:%d只輸出低32位的數據,並將這些32位二進制以十進制數輸出,編譯器首先將 7.5從float類型轉換為double類型,假設7.5在內存中的存放方式0x40f00000,轉換成double類型在內存中的數據就是這個0x401e000000000000,這個內存數據可以很明顯看出低32位全是0,而%d則只能截取到低32位,所以這個以%d輸出7.5的數值當然是 0了。如大家不相信可以用%lld 輸出看看,這個%lld就很讀到低64位數據,讀出的結果就是0x401e000000000000,在屏幕上看到一個很大的十進制數。
-
float f=7.5f; 如果用printf("%d",f);輸出的是0。 但float型用%d輸出是否一定是0 ? 答案肯定不都是0;
- 如果我一定要輸出7.5在內存中的存放方法怎么辦呢?
答:可以用printf("%d",*(int *)&f);這里做了一下處理,不是直接把a傳進來,把a所在地址里的內容處理了一下,不管a是什么類型,只對地址進行操作,利用(int *)&f,將a所在地址中的內容0x40f00000直接當成 int 類型傳給printf,int 的類型數據不會再轉成double類型了,所以輸出正常,這個只是針對浮點型數據只占低32位,如果輸出64位還得用%lld格式控制輸出。如果用printf("%d",(int)a),輸出行不行,這個強制類型轉換只針對a的數據類型進行轉換,7.5轉換 int 類型是7,而上面的*(int *)&f,是對內存中的實際存儲數據進行操作,蔽開數據類型這一層面,只將這個數據0x40f00000直接轉成int類型輸出。而(int)f,要先看a的類型,C語言會根據所要數據類型,對內存存儲的數據進行改變,以便可以用int類型正確解析內存數據。
-
如果用printf("%d",(float)f),輸出什么?
答:輸出的是0,這個只是將a的float類型還轉成float類型,還是自動轉成doube類型,傳給printf函數。
***********************int類型%f格式輸出************************************
- 如果定義了int a=0x40f00000;用printf("%f",f)輸出的結果是多少呢?
答案是0,至少我們看的屏幕上顯示的是0.000000,實際值可不是0啊,只是我們顯示的精度只能有15位小數,而實際的數據可能很小很小,0.0000....000幾百個0后會有幾個有效數據,我們分析一下。
首先C語言把a傳進printf,因為a是整型,所以不會自動轉成double型數據,直接將0x40f00000傳進printf,而%f尋的是64位內存,就把0x0000000040f00000這個內存中的數據當成浮點型輸出來,那浮點型的數據是多少呢,又是怎么存儲的呢?
64位浮點數的存放方式:
63位 62~52位 51~0位
1個符號位 11個階數 52個尾數
從0x0000000040f00000來看
1)符號位是0,表示正
2)階數是0,表示-1023 + 1023 = 0,用指數表示:1.#*2^-1023,‘#’是代表尾數。
3)尾數就是,0x0000040f00000
4)浮點二進制表示
2#1.0000000000000000000001000000111100000000000000000000*2^(-1023),-1023次方可想而知有多小。
這就是為什么我們的int型數據用%f輸出是0.000000的原因。
5. 總結:
通過以上實驗,我驗證了原假設基本正確:
格式輸出函數printf()根據類型字符%以及變量名,就可以根據數據首地址+讀取長度的方式輸出數據。
但是,還要注意其中的一些細節:
(1)用%d輸出float類型數據時,在參數傳遞的時候C語言統一將 float 類型數值傳換為 double 類型再傳入 printf 函數。而%d只截取低32位數據,所以得到的數字不是相應浮點數的二進制碼。
(2)int類型%f格式輸出,%f尋的是64位內存,所以輸出的數據可能很小(比如2^-1023),那么結果是0.