2013-02-08 64 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