C语言 当 int 被转换为 short 并被截断时,新值是如何确定的?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/34885966/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
When an int is cast to a short and truncated, how is the new value determined?
提问by buydadip
Can someone clarify what happens when an integer is cast to a shortin C? I'm using Raspberry Pi, so I'm aware that an intis 32 bits, and therefore a shortmust be 16 bits.
有人可以澄清short在 C 中将整数强制转换为 a 时会发生什么吗?我使用的是 Raspberry Pi,所以我知道 anint是 32 位,因此 ashort必须是 16 位。
Let's say I use the following C code for example:
例如,假设我使用以下 C 代码:
int x = 0x1248642;
short sx = (short)x;
int y = sx;
I get that xwould be truncated, but can someone explain how exactly? Are shifts used? How exactly is a number truncated from 32 bits to 16 bits?
我知道这x会被截断,但有人可以解释一下究竟是怎么回事吗?是否使用班次?一个数字是如何从 32 位截断到 16 位的?
回答by Keith Thompson
According to the ISO C standard, when you convert an integer to a signed type, and the value is outside the range of the target type, the result is implementation-defined. (Or an implementation-defined signal can be raised, but I don't know of any compilers that do this.)
根据 ISO C 标准,当您将整数转换为有符号类型,并且该值超出目标类型的范围时,结果是实现定义的。(或者可以引发实现定义的信号,但我不知道有任何编译器会这样做。)
In practice, the most common behavior is that the high-order bits are discarded. So assuming intis 32 bits and shortis 16 bits, converting the value 0x1248642will probably yield a bit pattern that looks like 0x8642. And assuming a two's-complement representation for signed types (which is used on almost all systems), the high-order bit is the sign bit, so the numeric value of the result will be -31166.
在实践中,最常见的行为是丢弃高位。因此假设int是 32 位和short16 位,转换该值0x1248642可能会产生一个看起来像0x8642. 并假设有符号类型的补码表示(几乎在所有系统上都使用),高位是符号位,因此结果的数值将为-31166。
int y = sx;
This also involves an implicit conversion, from shortto int. Since the range of intis guaranteed to cover at least the entire range of short, the value is unchanged. (Since, in your example, the value of sxhappens to be negative, this change of representation is likely to involve sign extension, propagating the 1sign bit to all 16 high-order bits of the result.)
这也涉及隐式转换,从short到int。由于 的范围int保证至少覆盖 的整个范围short,因此该值不变。(由于在您的示例中, 的值sx恰好为负,因此这种表示形式的更改可能涉及符号扩展,将1符号位传播到结果的所有 16 个高位。)
As I indicated, none of these details are required by the language standard. If you really want to truncate values to a narrower type, it's probably best to use unsigned types (which have language-specified wraparound behavior) and perhaps explicit masking operations, like this:
正如我所指出的,语言标准不需要这些细节。如果您真的想将值截断为更窄的类型,最好使用无符号类型(具有语言指定的环绕行为)和显式屏蔽操作,如下所示:
unsigned int x = 0x1248642;
unsigned short sx = x & 0xFFFF;
If you have a 32-bit quantity that you want to shove into a 16-bit variable, the first thing you should do is decide how you want your code to behave if the value doesn't fit. Once you've decided that, you can figure out how to write C code that does what you want. Sometimes truncation happens to be what you want, in which case your task is going to be easy, especially if you're using unsigned types. Sometimes an out-of-range value is an error, in which case you need to check for it and decide how to handle the error. Sometimes you might want the value to saturate, rather than truncate, so you'll need to write code to do that.
如果您想将一个 32 位的数量推入一个 16 位的变量中,那么您应该做的第一件事就是决定如果该值不适合您希望代码的行为方式。一旦确定了这一点,您就可以弄清楚如何编写符合您要求的 C 代码。有时截断恰好是您想要的,在这种情况下,您的任务会很容易,尤其是当您使用无符号类型时。有时超出范围的值是一个错误,在这种情况下,您需要检查它并决定如何处理错误。有时您可能希望值饱和,而不是截断,因此您需要编写代码来做到这一点。
Knowing how conversions work in C is important, but if you startwith that question you just might be approaching your problem from the wrong direction.
了解 C 中的转换是如何工作的很重要,但如果你从这个问题开始,你可能会从错误的方向解决你的问题。
回答by Amit
The 32 bit value is truncated to 16 bits in the same way a 32cm long banana bread would be cut if you jam it into a 16cm long pan. Half of it would fit in and still be a banana bread, and the rest will be "gone".
32 位的值被截断为 16 位,就像将 32 厘米长的香蕉面包塞入 16 厘米长的平底锅时切掉的方式一样。一半可以放进去,仍然是香蕉面包,其余的将“消失”。
回答by edmz
Truncation happens in CPU registers. These have different sizes: 8/16/32/64 bits. Now, you can imagine a register like:
截断发生在 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
xis first given the 32 bit value 0x1248642. In memory*, it'll look like:
x首先给出 32 位值0x1248642。在内存中*,它看起来像:
-----------------------------
| 01 | 24 | 86 | 42 |
-----------------------------
31..24 23..16 15..8 7..0
Now, the compiler loads xin a register. From it, it can simply load the least significant 16 bits (namely, ax) and store them into sx.
现在,编译器加载x到寄存器中。从中,它可以简单地加载最低有效的 16 位(即,ax)并将它们存储到sx.
*Endianness is not taken into account for the sake of simplicity
*为简单起见,不考虑字节序
回答by Dan Bechard
Perhaps let the code speak for itself:
也许让代码不言自明:
#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;
}
Output:
输出:
19170882
34370
-31166
x: 00000001 00100100 10000110 01000010
sx: 10000110 01000010
y: 11111111 11111111 10000110 01000010
As you can see, int-> shortyields the lower 16 bits, as expected.
正如你所看到的,int->short产生了低 16 位,正如预期的那样。
Casting shortto intyields the shortwith the 16 high bits set. However, I suspect this is implementation specific and undefined behavior. You're essentially interpreting 16 bits of memory as an integer, which reads 16 extra bits of whatever rubbish happens to be there (or 1's if the compiler is nice and wants to help you find bugs quicker).
铸造short到int产率short与设定的16个高位。但是,我怀疑这是实现特定的和未定义的行为。您实际上是将 16 位内存解释为一个整数,它会读取 16 位额外的任何垃圾(如果编译器很好并希望帮助您更快地找到错误,则为 1)。
I thinkit should be safe to do the following:
我认为执行以下操作应该是安全的:
int y = 0x0000FFFF & sx;
Obviously you won't get back the lost bits, but this will guarantee that the high bits are properly zeroed.
显然你不会找回丢失的位,但这将保证高位正确归零。
If anyone can verify the short -> int high bit behavior with an authoritative reference, that would be appreciated.
如果有人可以使用权威参考来验证 short -> int 高位行为,那将不胜感激。
Note: Binary macro adapted from this answer.
注意:根据此答案改编的二进制宏。
回答by Zbynek Vyskovsky - kvr000
Simply the high 16 bits are cut off from the integer. Therefore your short will become 0x8642which is actually negative number -31166.
简单地从整数中截取高 16 位。因此,您的空头将变为0x8642实际上是负数-31166。
回答by nsilent22
sxvalue will be the same as 2 least significant bytes of x, in this case it will be 0x8642 which (if interpreted as 16 bit signed integer) gives -31166 in decimal.
sxvalue 将与 的 2 个最低有效字节相同x,在这种情况下,它将是 0x8642,它(如果解释为 16 位有符号整数)给出 -31166 十进制。

