float類型%d輸出
float a=7.5f;
如果用printf("%d",a);輸出的是0。
但float型用%d輸出是否一定是0呢,答案肯定不都是0;
為什么 7.5 用%d輸出的是0?分析如下:
首先來了解下printf的輸出格式,int 和 long int 都是32位的,用%d輸出;float 、double都是%f輸出,但 float 是32位的,double 是64位的,所以在參數傳遞的時候C語言統一將 float 類型數值傳換為 double 類型再傳入 printf 函數。如果是32位整型則輸出格式為%lld。
下面來講一下 float a=7.5f ; printf("%d",a)輸出為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,在屏幕上看到一個很大的十進制數。
如果我一定要輸出7.5在內存中的存放方法怎么辦呢?
可以用printf("%d",*(int *)&a);這里做了一下處理,不是直接把a傳進來,把a所在地址里的內容處理了一下,不管a是什么類型,只對地址進行操作,利用(int *)&a,將a所在地址中的內容0x40f00000直接當成 int 類型傳給printf,int 的類型數據不會再轉成double類型了,所以輸出正常,這個只是針對浮點型數據只占低32位,如果輸出64位還得用%lld格式控制輸出。
如果用printf("%d",(int)a),輸出行不行,這個強制類型轉換只針對a的數據類型進行轉換,7.5轉換 int 類型是7,而上面的*(int *)&a,是對內存中的實際存儲數據進行操作,蔽開數據類型這一層面,只將這個數據0x40f00000直接轉成int類型輸出。而(int)a,要先看a的類型,C語言會根據所要數據類型,對內存存儲的數據進行改變,以便可以用int類型正確解析內存數據。
如果用printf("%d",(float)a),輸出什么,輸出的是0,這個只是將a的float類型還轉成float類型,還是自動轉成doube類型,傳給printf函數。
為什么float非要轉成double類型呢,因為printf格式控制浮點型輸出只有%f,所以統一按doube類型輸出,不像整型有32位的%d或%ld,64位的有%lld,這就將32位整型和64位整型用不同的格式控制分開了,而%f則沒有,所以printf輸出的浮點數其實是統一遍歷了64位內存,如果float傳入printf沒有進行轉換,那么printf輸出高32位數據將不可預知,printf輸出結果也就不正確了,因此傳入printf的浮點數都會被編譯器隱含轉成double類型。
***********************int類型%f格式輸出************************************
如果定義了int a=0x40f00000;用printf("%f",a)輸出的結果是多少呢?
答案是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的原因。