printf("%d",5.01)和printf("%f",5)的輸出結果

  1. printf("%f\n",5);  
  2. printf("%d\n",5.01);   
  3. printf("%f\n", (float)5);    
  4. printf("%f\n", 5.f);    


輸出結果:程序員

看到結果,會感受很是奇怪。1處怎麼會輸出0呢?2又爲什麼會顯示這麼大的一個數呢?面試

解釋:安全

下面是轉自網上的一篇博客的解釋函數

1,之因此沒輸出5,這是C語言設計的緣由。
2,之因此輸出0,這是計算機體系結構的問題。
spa

具體來講:.net

printf函數不會進行任何類型轉換,它只是從內存中讀出你所提供的元素的值(按照 %d,%f等控制字符提示的格式)。C語言設計中,int類型通常是32bit或者16bit,而float通常是64bit,而且有可能使用科學計數保 存。這點就和huhugo88所說同樣,5在內存中爲00000000,00000101。並且5通常都在靜態區,程序的靜態存儲區默認是0,那麼當 用%f來讀時,就會讀64bit,也就是會讀以前的不少位0,最後按照(有效數字)×(基數2)pow(指數)的方式來取數,天然結果是0設計

之因此Vc中不容許這種狀況,而有些編譯器就容許這麼輸出就是編譯器設置的問題。按理 說,這樣訪問內存是屬於越界訪問,應該禁止。不過只是讀,傷害性不大而已。  對於單精度浮點數(32bit),很多c語言編譯系統以24位表示小數部分(包括1bit符號位),以8位表示指數部分。 ==========================printf("%d\n",5.01);  爲何輸出一個大數?在講這個題目以前,預備知識,講一下,printf函數,輸入參數是讀入緩衝區保存,再按照%?的格式從緩衝區中讀出數據,並據此格 式解釋數據。3d

有了這個知識以後,在講程序員面試寶典上看到一個題:orm

 

#include "stdio.h" 
int main(int argc, char* argv[])   
{   
    printf("%d\n",5.01);   
return 0;   
}   
輸出結果爲:188978561  
而後開始研究爲何會是這個數?
blog

5.01是double類型,內存中佔8個字節,保存在緩衝區。而%d爲整型,佔4個 字節,printf從緩衝區中讀入4字節,先讀到低32位的數據。也就是說printf輸出的應該是5.01以double類型保存數劇的低32位。爲了 檢驗此結果是否正確,對比5.01在內存中的表示與輸出。

 

#include "stdio.h" 
int main(int argc, char* argv[])   
{   
double d = 5.01;   
int *p = (int *)(&d);   
int rst = 1889785610;   
    printf("1).%x\n",*p);   
    printf("2).%x\n",*(p+1));   
    printf("3).%x\n",rst);   
return 0;   
}   
輸出爲:   
1).0x70a3d70a   
2).0x40140a3d   
3).0x70a3d70a  
這也就證實了%d輸出了5.01的低32低。5.01的double類型,在內存的的表示爲0x40140a3d70a3d70a。

事情看似也就完成了。

我又想,若是輸入是浮點類型的5.01f,又會發生什麼呢?

 

#include "stdio.h" 
int main(int argc, char* argv[])   
{   
float f = 5.01f;     
int *p = (int *)(&f);        
    printf("1).0x%x\n",*p);     
    printf("2).0x%x\n",5.01f);     
return 0;     
}   
輸出:   
1).0x40a051ec   
2).0x80000000  
咱們發現,此時輸出的並非浮點類型5.01f的內存的表示,這是爲何呢?

而後看到一個說法,是printf會把%f按double類型輸出,也就是說會把參數float型的轉成double型在輸出。

但如今並非%f,固然用%f顯示的是正確的結果。因而我猜想,printf是將所在float型讀入的數據都自動的轉化爲double型了,而後%f就按double處理,而咱們這是%d,因此顯示的爲float轉化爲double型後的低4字節。

驗證此想法:

 

#include "stdio.h" 
int main(int argc, char* argv[])   
{   
double f = 5.01;     
int *p = (int *)(&f);   
    printf("1).0x%x\n",*p);   
    printf("2).0x%x\n",*(p+1));     
    printf("3).0x%x\n",5.01f);     
return 0;     
}   
輸出:   
1).0x70a3d70a   
2).0x40140a3d   
3).0x80000000  
可是咱們發現結果並不同,因而我又猜測,也是許printf將float轉化爲double的方式與默認的方式不同

5.01d的默認的表示爲:0x40140a3d70a3d70a,在上面已經說明了

 

#include "stdio.h" 
int main(int argc, char* argv[])   
{   
    printf("0x%8x\n0x%8x\n",5.01f);   
return 0;   
}   
輸出爲:   
0x80000000   
0x40140a3d  
與是發現printf將5.01f->5.01d的表示是:0x40140a3d80000000

接着就是看這兩個值是否都是爲5.01了:

view plaincopy to clipboardprint?

#include "stdio.h" 
int main(int argc, char* argv[])   
{   
int d1[2], d2[2];   
    d1[0]=0x80000000;   
    d1[1]=0x40140a3d;   
    d2[0]=0x70a3d70a;   
    d2[1]=0x40140a3d;   
double *p1 = (double *)d1;   
double *p2 = (double *)d2;   
    printf("1).%f\n",*p1);   
    printf("2).%f\n",*p2);   
return 0;     
}   
輸出爲:   
1).5.010000   
2).5.010000  
也就證實了0x40140a3d80000000,與0x40140a3d70a3d70a都是5.01d在機器中的表示。前者爲5.01f(0x40a051ec)由printf轉化爲double後的表示,後者爲5.01d的默認的表示。

總結:printf將輸的浮點型參數全都自動轉化爲雙精度型,且與默認的雙精度的表示方法是不一樣的。最重要一點,printf不安全,類型不安全,要是類型不對了,也許咱們就掛了^_^


本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/fengyunjh/archive/2011/03/07/6230164.aspx

相關文章
相關標籤/搜索