当一个整数在C语言中被强制转换为short
类型时会发生什么?我正在使用树莓派,所以我知道int
类型是32位的,因此short
类型必须是16位。
举个例子,假设我使用以下C代码:
int x = 0x1248642;
short sx = (short)x;
int y = sx;
我知道 x
会被截断,但有人能解释一下具体是如何做到的吗?使用移位操作吗?一个32位的数字具体如何被截断成16位?
int y = sx;
这也涉及到一个隐式转换,从short
到int
。由于int
的范围保证至少覆盖了整个short
的范围,所以该值不变。(因为在您的示例中,sx
的值恰好为负,所以这种表示的改变很可能涉及符号扩展,将1
符号位传播到结果的所有16个高位比特中。)unsigned int x = 0x1248642;
unsigned short sx = x & 0xFFFF;
如果您有一个32位的值想要存储到16位变量中,首先需要决定在数值不匹配时程序应该如何运行。一旦您做出了决定,就可以考虑如何编写符合您需求的C代码。有时候截断可能是您需要的结果,这种情况下任务会比较简单,尤其是使用无符号类型的情况下。有时候超出范围的值是一个错误,这种情况下您需要检查并决定如何处理错误。有时候您可能希望值饱和而不是截断,因此您需要编写相应的代码。
了解C语言中的转换方式是很重要的,但是如果您从这个问题开始,可能会从错误的方向入手解决问题。
x
可以适应一个 short 类型,那么你可以使用 assert( x <= USHRT_MAX )
来强制执行这个假设,而不是进行掩码操作。 - SchwernCHAR_BIT != 8
,则 x & 0xFFF
!= (short) x
。 - edmz32位的值会以类似于将32cm长的香蕉面包塞入16cm长烤盘中切割的方式被截断为16位。其中一半可以适应并仍然是个香蕉面包,而另一半则会“消失”。
截断发生在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
x
首先被赋予32位值0x1248642
。在内存中,它看起来像:
-----------------------------
| 01 | 24 | 86 | 42 |
-----------------------------
31..24 23..16 15..8 7..0
x
加载到一个寄存器中。然后,它可以简单地加载最低有效的16位(即ax
),并将它们存储到sx
中。
#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
-> short
转换会产生预期的低16位。
将short
强制转换为int
会导致设置了16个高位的short
。但是,我怀疑这是实现特定和未定义的行为。本质上,您正在将16位内存解释为整数,这读取了16个额外的垃圾(如果编译器友好并希望帮助您更快地找到错误,则为1)。
我认为以下操作应该是安全的:
int y = 0x0000FFFF & sx;
显然,您无法恢复丢失的位,但这将确保高位被正确清零。
如果有人能够通过权威参考验证短->整数高位行为,那将不胜感激。
注意:二进制宏改编自this answer。
简单来说,这个整数的高16位将被截断掉。因此你的短整数将变成0x8642
,实际上是负数-31166
。
sx
的值将与x
的最后两个字节相同,在这种情况下,它将是0x8642,如果解释为16位带符号整数,则十进制为-31166。
0x8642
在十进制中不是-31166
。0x8642
在十进制中是34370
。当将该值转换为16位有符号类型时,通常会得到-31166
,但那是一个不同的值。 - Keith Thompson
short sx = x;
,并且x
的值将被隐式转换为short
。 - Keith Thompson#include <stdint.h>
来引入int32_t
、int16_t
等,从而消除位宽猜测。 - rubicks