当int被强制转换为short并被截断时,新值是如何确定的?

时间:2016-01-19 20:05:21

标签: c casting truncate

有人可以澄清当一个整数转换为C中的short时会发生什么吗?我正在使用Raspberry Pi,所以我知道int是32位,因此short必须是16位。

假设我使用以下C代码:

int x = 0x1248642;
short sx = (short)x;
int y = sx;

我认为x会被截断,但有人可以解释一下究竟是怎么回事?轮班使用了吗?数字究竟是如何从32位截断到16位的?

6 个答案:

答案 0 :(得分:38)

根据ISO C标准,当您将整数转换为有符号类型,并且该值超出目标类型的范围时,结果是实现定义的。 (或者可以引发实现定义的信号,但我不知道任何执行此操作的编译器。)

实际上,最常见的行为是丢弃高位。因此,假设int为32位且short为16位,则转换值0x1248642可能会产生类似于0x8642的位模式。假设有符号类型的二进制补码表示(几乎在所有系统上都使用),高位是符号位,因此结果的数值将为-31166。 / p>

int y   =   sx;

这还涉及从shortint的隐式转换。由于保证int的范围至少涵盖short的整个范围,因此该值不变。 (因为在您的示例中,sx的值恰好为负值,此表示更改可能涉及符号扩展,将1符号位传播到所有16结果的高位。)

正如我所说,语言标准不需要这些细节。如果你真的想要将值截断为更窄的类型,那么最好使用无符号类型(具有语言指定的环绕行为)以及可能的显式屏蔽操作,如下所示:

unsigned int x = 0x1248642;
unsigned short sx = x & 0xFFFF;

如果您要将32位数量推送到16位变量中,那么您应该做的第一件事就是决定如果值不合适,您希望代码的行为方式如何。一旦你决定了,你就可以弄清楚如何编写符合你想要的C代码。有时截断恰好是您想要的,在这种情况下,您的任务将很容易,特别是如果您使用的是无符号类型。有时超出范围的值是错误,在这种情况下,您需要检查它并决定如何处理错误。有时您可能希望该值饱和而不是截断,因此您需要编写代码来执行此操作。

了解转化如何在C中发挥作用非常重要,但如果你开始这个问题,你可能会从错误的方向接近你的问题。

答案 1 :(得分:11)

32位值被截断为16位,就像将一个32厘米长的香蕉面包切成16厘米长的平底锅一样。其中一半适合并且仍然是香蕉面包,其余的将是"消失了#34;。

答案 2 :(得分:6)

截断发生在CPU寄存器中。它们有不同的大小:8/16/32/64位。现在,您可以想象一个如下的寄存器:

x

0x1248642首先获得32位值----------------------------- | 01 | 24 | 86 | 42 | ----------------------------- 31..24 23..16 15..8 7..0 。在内存*中,它看起来像:

x

现在,编译器在寄存器中加载ax。从中,它可以简单地加载最低有效16位(即sx)并将它们存储到 <form> <div class="input-field"> <p class="range-field"> <input type="range" id="test5" min="0" max="100" /> </p> </div> </form>

*为简单起见,不考虑字节顺序

答案 3 :(得分:4)

只需从整数中删除高16位。因此,您的空头将变为0x8642,实际上是负数-31166

答案 4 :(得分:4)

或许让代码说明一切:

#include <stdio.h>

#define BYTETOBINARYPATTERN "%d%d%d%d%d%d%d%d"
#define BYTETOBINARY(byte)  \
   ((byte) & 0x80 ? 1 : 0), \
   ((byte) & 0x40 ? 1 : 0), \
   ((byte) & 0x20 ? 1 : 0), \
   ((byte) & 0x10 ? 1 : 0), \
   ((byte) & 0x08 ? 1 : 0), \
   ((byte) & 0x04 ? 1 : 0), \
   ((byte) & 0x02 ? 1 : 0), \
   ((byte) & 0x01 ? 1 : 0) 

int main()
{
    int x    =   0x1248642;
    short sx = (short) x;
    int y    =   sx;

    printf("%d\n", x);
    printf("%hu\n", sx);
    printf("%d\n", y);

    printf("x: "BYTETOBINARYPATTERN" "BYTETOBINARYPATTERN" "BYTETOBINARYPATTERN" "BYTETOBINARYPATTERN"\n",
        BYTETOBINARY(x>>24), BYTETOBINARY(x>>16), BYTETOBINARY(x>>8), BYTETOBINARY(x));

    printf("sx: "BYTETOBINARYPATTERN" "BYTETOBINARYPATTERN"\n",
        BYTETOBINARY(y>>8), BYTETOBINARY(y));

    printf("y: "BYTETOBINARYPATTERN" "BYTETOBINARYPATTERN" "BYTETOBINARYPATTERN" "BYTETOBINARYPATTERN"\n",
        BYTETOBINARY(y>>24), BYTETOBINARY(y>>16), BYTETOBINARY(y>>8), BYTETOBINARY(y));

    return 0;
}

输出:

19170882
34370
-31166

x: 00000001 00100100 10000110 01000010
sx: 10000110 01000010
y: 11111111 11111111 10000110 01000010

如您所见,int - &gt;正如预期的那样,short产生低16位。

short转换为int会产生short,并设置16个高位。但是,我怀疑这是特定于实现和未定义的行为。你实际上是将16位内存解释为一个整数,它会读出16个额外位的垃圾(如果编译器很好并且希望帮助你更快地发现错误,则读取1个。)

认为执行以下操作应该是安全的:

int y = 0x0000FFFF & sx;

显然你不会找回丢失的位,但这可以保证高位被正确归零。

如果有人可以验证短 - &gt;使用权威引用的高位行为,这将是值得赞赏的。

注意:二进制宏改编自this answer

答案 5 :(得分:2)

sx值与x的2个最低有效字节相同,在这种情况下,它将是0x8642(如果解释为16位有符号整数),则给出-31166十进制。