2014-11-05 21 views
1

C99標準區分隱式和顯式類型轉換(6.3轉換)。我猜,但無法找到隱式強制轉換,當目標類型的精度比源更高時,可以表示它的值。 [這是我認爲從INT到DOUBLE發生的事情]。鑑於此,我在看下面的例子:瞭解printf的隱式轉換

#include <stdio.h> // printf 
#include <limits.h> // for INT_MIN 
#include <stdint.h> // for endianess 
#define IS_BIG_ENDIAN (*(uint16_t *)"\0\xff" < 0x100) 

int main() 
{ 
    printf("sizeof(int): %lu\n", sizeof(int)); 
    printf("sizeof(float): %lu\n", sizeof(float)); 
    printf("sizeof(double): %lu\n", sizeof(double)); 
    printf(IS_BIG_ENDIAN == 1 ? "Big" : "Little"); printf(" Endian\n"); 

    int a = INT_MIN; 
    printf("INT_MIN: %i\n", a); 
    printf("INT_MIN as double (or float?): %e\n", a); 
} 

我很驚訝地發現,輸出:

sizeof(int): 4 
sizeof(float): 4 
sizeof(double): 8 
Little Endian 
INT_MIN: -2147483648 
INT_MIN as double (or float?): 6.916919e-323 

所以打印的浮點值接近很小低於正常正次正規浮點數雙倍4.9406564584124654×10^-324。奇怪的事情發生了,當我註釋掉兩個printf進行字節序,我得到另一個值雙:

#include <stdio.h> // printf 
#include <limits.h> // for INT_MIN 
#include <stdint.h> // for endianess 
#define IS_BIG_ENDIAN (*(uint16_t *)"\0\xff" < 0x100) 

int main() 
{ 
    printf("sizeof(int): %lu\n", sizeof(int)); 
    printf("sizeof(float): %lu\n", sizeof(float)); 
    printf("sizeof(double): %lu\n", sizeof(double)); 
    // printf(IS_BIG_ENDIAN == 1 ? "Big" : "Little"); printf(" Endian\n"); 

    int a = INT_MIN; 
    printf("INT_MIN: %i\n", a); 
    printf("INT_MIN as double (or float?): %e\n", a); 
} 

輸出:

sizeof(int): 4 
sizeof(float): 4 
sizeof(double): 8 
INT_MIN: -2147483648 
INT_MIN as double (or float?): 4.940656e-324 
  • 的gcc --version:(Ubuntu的4.8.2- 19ubuntu1)4.8.2
  • UNAME:x86_64的GNU/Linux的
  • 編譯選項,其中:GCC -OX XC -Wall -Wextra -std = C99 --pedantic
  • 是的,其中有一個警告:
x.c: In function ‘main’: 
x.c:15:3: warning: format ‘%e’ expects argument of type ‘double’, but argument 2 
      has type ‘int’ [-Wformat=] 

    printf("INT_MIN as double (or float?): %e\n", a); 
^

但我還是不明白究竟發生了什麼。

    在小字節序
  • 我認爲MIN_INT爲:00 ... 0001 MIN_DBL(低於正常)爲100..00#,從尾數,其次是指數,並與#爲符號位的結論。
  • 這是在int上應用「%e」格式說明符的一種形式,是一種隱式轉換?,一種reinterpret轉換?

我迷路了,請使我高興。

+2

''cast'-ing和爲'printf()'提供不兼容的'格式說明符'是有區別的。後來的行動導致UB。 – 2014-11-05 07:07:01

+0

我建議你修改你的代碼,使其具有一個正確的printf和一個不正確的printf,然後編譯爲程序集並查看兩者之間的區別。你會發現double應該在可變參數函數中傳遞,以及它如何試圖將int作爲double來傳遞。 – JS1 2014-11-05 07:17:31

回答

2
printf("INT_MIN as double (or float?): %e\n", a); 

上方有問題您不能使用%e來打印整數。行爲是未定義的。

您應該使用

printf("INT_MIN as double (or float?): %e\n", (double)a); 

double t = a; 
printf("INT_MIN as double (or float?): %e\n", t); 

Related post:這篇文章介紹瞭如何在printf中使用了不正確的打印符可導致UB。

+0

相關帖子非常有幫助。 – math 2014-11-05 07:05:40

+0

@math我很高興它幫助。 – 2014-11-05 07:07:18

0

va_arg的參數不會被轉換,在語法上,編譯器對這些函數的參數一無所知,所以他不能這樣做。現代編譯器確實知道解釋格式字符串,所以他們能夠在發生可疑事件時提醒你。當你看到gcc的警告時就會發生這種情況。

爲了更精確,有一些優惠了爲整數類型完成,它們被晉升爲int,以及用於float其被晉升爲double。但這就是所有可能發生的魔法。

總之,總是使用正確的格式說明符。

順便說一句,對於size_t截止到您的sizeof表達式正確的是%zu