我有:
int a = 2147483647;
short b = (short)a;
我得到了b = -1
,而我希望int32
被转换为int16
(short
)。我希望看到一些价值而不是 -1
.
请有人帮我解决这个问题。
值 2147483647 或 2 31 -1 溢出 16 位整数。它的二进制表示在 MSB 中为零,其余位中为 31 个 1。
看起来在您的实现中,最后 16 位被转换为short
. 发生这种情况时,它们都设置为1
,从而产生 的2 的补码表示-1
:
32-bit int: 01111111111111111111111111111111
16-bit short: ----------------1111111111111111
但是,2-compliment 表示和这种行为通常都不是 C++ 标准的一部分,因此这种行为是实现定义的。
将值转换为有符号类型,当源值不适合目标类型时,会产生实现定义的结果。这意味着任何符合标准的编译器的文档都必须记录结果是什么。
(这与算术运算符溢出时的行为不同。例如:
int overflow = INT_MAX + 1;
实际上有未定义的行为。但无论哪种情况,您都应该小心编写代码,以免引发此类问题。)
对于许多实现,对于转换和算术来说,目标是 N 位类型的溢出只需要正确结果的 N 个低位。
在您的情况下,显然int
是 32 位和short
16 位(这些大小可能因不同的实现而异)。2147483647
是0x7fffffff
,低 16 位是0xffff
,这是(同样,在您的实现中)-1
in 类型的表示short
。
对于转换为无符号类型,结果由标准严格定义;它取结果的低 N 位。对于溢出的浮点转换(例如,将一个非常大的double
值转换为float
),行为是未定义的。
到目前为止,这对于 C 和 C++ 来说都是一样的。但只是为了增加混乱,从 1999 年标准开始,允许溢出的有符号转换来引发实现定义的信号。C++ 没有这个。我不知道实际上有任何编译器可以做到这一点。
我希望看到一些价值而不是
-1
.
-1
是“一些价值”。有没有你期望的特定价值?
顺便:
short b = (short)a;
演员阵容是不必要的。赋值、初始化、参数传递和return
语句可以在任何数字类型之间赋值,而无需强制转换。该值被隐式转换:
short b = a;
这是implementation defined
行为,例如gcc
Integers Implementation document
说:
为了转换为宽度为 N 的类型,该值以2^N 为模减少到该类型的范围内;没有发出信号。
这可能因编译器而异,我无法为clang
nor挖掘类似的文档visual studio
。
来自 C++ 标准草案,段落4.7 Integral conversions
段落3
:
如果目标类型是有符号的,则如果它可以在目标类型(和位域宽度)中表示,则该值不变;否则,该值是实现定义的。
如果是这样unsigned
,那么根据段落,您将拥有完美定义的行为2
:
如果目标类型是无符号的,则结果值是与源整数一致的最小无符号整数(模 2n,其中 n 是用于表示无符号类型的位数)。[ 注意:在二进制补码表示中,这种转换是概念性的,位模式没有变化(如果没有截断)。——尾注]
C99
标准草案部分的语言类似6.3.1.3 Signed and unsigned integers
。
您的 int A 大于 short 的大小。当您将 A 转换为 short 时,您会在最左边得到一个 1,这将表明它是一个负数。因为你得到 -1,我想你在所有 16 位中得到 1,这将给你 -2^15 + 2^14 + 2^13... + 2^0,这会给你-1。简而言之(没有双关语),如果整数太大,则无法将整数转换为短整数。
你可以这样做:
uint32_t sum=0xFFFF1234;
uint16_t *p= (uint16_t *) ∑
uint16_t checksum=p[0];
校验和是0x1234
。
这是另一种方式:
union ToShort
{
uint32_t sum;
uint16_t checksum[2];
} toShort;
toShort.sum=0xFFFF1234;
cout << hex << toShort.checksum[0];
输出是1234
。