隐式地抛出一个浮点常数

时间:2013-02-08 14:17:40

标签: c casting floating-point

请看一下这段代码:

#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;之间的区别是什么?

2 个答案:

答案 0 :(得分:13)

因为如果浮点值的整数部分在新类型中无法表示,则转换是未定义的行为。

在您的情况下,SHRT_MAX可能是32767,因此65696.0F的组成部分无法在short对象中表示。

答案 1 :(得分:1)

这是“未定义的行为”,这意味着编译器可以自由地执行它想要的操作。但“未定义”并不意味着“无法解释”。

编译器在s = f的情况下正在做的是将f首先转换为int值65696,然后将65696分配给s,溢出并离开160.编译器这是因为有一条CPU指令将浮点数转换为32位整数,但不直接转换为16位整数

编译器使用s = 65696.0F做的更简单:它知道65696.0超出范围,因此它为s分配了最高值,恰好是2 ^ 15-1 = 32767

如果您读取编译器为s = f生成的汇编代码(例如使用带有gcc的-S开关),则可以验证这一点:

    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。

它为s = 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