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;

4

2 回答 2

13

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

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

于 2013-02-08T14:19:40.993 回答
1

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

在这种情况下编译器所做的s = ff首先转换为int值 65696,然后将 65696 分配给 s,这会溢出并留下 160。编译器这样做是因为有一条 CPU 指令将浮点数转换为 32-位整数,但不直接转化为 16 位整数

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

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

    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
于 2013-02-08T15:20:38.430 回答