2013-02-08 58 views
10

請看看下面的代碼:隱式鑄造浮動常數

#include <stdio.h> 

int main(void) 
{ 
    short s; 
    int i = 65696; 
    float f = 65696.0F; 

    printf("sizeof(short) = %lu\n", sizeof(short)); 

    s = i; 
    printf("s = %hd\n", s); 
    s = f; 
    printf("s = %hd\n", s); 

    s = 65696; 
    printf("s = %hd\n", s); 
    s = 65696.0F; 
    printf("s = %hd\n", s); 

    return 0; 
} 

它給作爲輸出:

sizeof(short) = 2 
s = 160 
s = 160 
s = 160 
s = 32767 

在最後一行爲什麼它是32767,而不是160?說f = 65696.0F; s = f;s = 65696.0F;有什麼區別?

回答

13

因爲如果float值的整數部分在新類型中不可表示,則轉換爲未定義行爲。

在您的情況下,SHRT_MAX可能是32767,因此65696.0F的組成部分不能在short對象中表示。

+7

+1。具體而言,6.3.1.4/1:*「當實際浮點類型的有限值被轉換爲除_Bool以外的整數類型時,小數部分被丟棄(即該值被截斷爲零)。如果整數部分不能用整數類型表示,行爲是不確定的)「* – Jon 2013-02-08 14:21:32

+0

@Jon爲什麼當我說'f = 65696.0F; s = f'? – rootkea 2013-02-08 14:22:40

+3

@rootkea這是未定義的行爲,以及是未定義的行爲可能是不可預測的。 – ouah 2013-02-08 14:24:31

1

這是「未定義的行爲」,這意味着編譯器可以自由地做它想做的事情。但「未定義」並不意味着「無法解釋」。

什麼編譯器正在做的s = f的情況下轉換f第一至int值65696,然後分配到65696 s,這溢出並離開160編譯器這樣做是因爲有一個CPU指令轉換將浮點數轉換爲32位整數,但不能直接轉換爲16位整數

編譯器與s = 65696.0F做什麼更簡單:它知道65696.0超出範圍,因此它將可用的最高值分配給s,恰好是2^15-1 = 32767.

您可以驗證這是否你讀彙編代碼(使用-S開關用gcc例如)對於s = F編譯器生成:

movss -4(%rbp), %xmm0  # Load float from memory into register xmm0 
    cvttss2si  %xmm0, %eax # Convert float in xmm0 into signed 32 bit, store in eax 
    movw %ax, -10(%rbp)   # Store lower 16 bits of eax into memory 
    movswl -10(%rbp), %eax  # Load those 16 bits into eax, with sign extend 

最後一條指令則會覆蓋%eax中的高16位,在這種情況下,設置爲全0 。

它產生了叫什麼= 65696.0F簡單:

movw $32767, -10(%rbp)  # Store the lower 16 bits of 32767 into memory 
    movswl -10(%rbp), %eax  # Load those 16 bits into eax, with sign extend