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

Bol*_*boa 36 c casting truncate

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

假设我使用以下C代码作为示例:

int x = 0x1248642;
short sx = (short)x;
int y = sx;
Run Code Online (Sandbox Code Playgroud)

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

Kei*_*son 39

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

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

int y   =   sx;
Run Code Online (Sandbox Code Playgroud)

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

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

unsigned int x = 0x1248642;
unsigned short sx = x & 0xFFFF;
Run Code Online (Sandbox Code Playgroud)

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

了解转换在C中的工作方式非常重要,但如果问题开始,您可能会从错误的方向接近您的问题.


Ami*_*mit 12

32位值被截断为16位,如果将其塞入16厘米长的平底锅中,则会切割32厘米长的香蕉面包.其中一半适合并仍然是香蕉面包,其余的将"消失".

  • 不是最好的比喻.我可以将一个32厘米的香蕉放入一个16厘米的锅中,方法是将其粉碎或将其切成两个并排的碎片.一个单词中的比特比平底锅中的香蕉比特具有更严格的约束.而且你没有说明你最终的一半,或者为什么. (3认同)
  • 大小问题`;-)` (2认同)
  • 当且仅当您的香蕉面包是“未签名的”时:) (2认同)

edm*_*dmz 7

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

<--rax----------------------------------------------------------------> (64-bit)
                                    <--eax----------------------------> (32-bit)
                                                      <--ax-----------> (16-bit)
                                                      <--ah--> <--al--> (8-bit high & low)
01100011 01100001 01110010 01110010 01111001 00100000 01101111 01101110
Run Code Online (Sandbox Code Playgroud)

x首先给出32位值0x1248642.在内存*中,它看起来像:

-----------------------------
|  01  |  24  |  86  |  42  |
-----------------------------
 31..24 23..16 15..8  7..0       
Run Code Online (Sandbox Code Playgroud)

现在,编译器加载x到寄存器中.从它,它可以简单地加载最低有效16位(即,ax)并存储它们sx.


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


Zby*_*000 5

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

  • @ ZbynekVyskovsky-kvr000:否,将超出范围的值转换为带符号类型的结果是实现定义的。请参阅[N1570](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf)6.3.1.3节。(丢弃高阶位当然是最常见的行为。) (4认同)

Dan*_*ard 5

也许让代码说明一切:

#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;
}
Run Code Online (Sandbox Code Playgroud)

输出:

19170882
34370
-31166

x: 00000001 00100100 10000110 01000010
sx: 10000110 01000010
y: 11111111 11111111 10000110 01000010
Run Code Online (Sandbox Code Playgroud)

如您所见,int-> short产生了低16位,与预期的一样。

强制转换shortint产生short16位高位的。但是,我怀疑这是特定于实现且未定义的行为。您实际上是将16位内存解释为一个整数,它会读取垃圾中可能出现的16位多余的位(如果编译器很好,并且希望帮助您更快地发现错误,则读取1位)。

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

int y = 0x0000FFFF & sx;
Run Code Online (Sandbox Code Playgroud)

显然,您不会找回丢失的位,但这将确保高位正确归零。

如果任何人都可以通过权威参考来验证short-> int high bit行为,将不胜感激。

注意:二进制宏改编自此答案

  • 这仅显示您用于生成输出的实现的行为。 (4认同)