我有:
int a = 2147483647;
short b = (short)a;
我得到了b = -1
,但我期望将int32
转换为int16
(short
)。我希望看到一些值,而不是-1
。
请有人帮助我解决这个问题。
值2147483647或231-1溢出了16位整数。它的二进制表示在MSB为零,其余位是31个1。
看起来在你的实现中,在转换为short
时,取了最后16位。当这种情况发生时,它们全部设置为1
,导致了一个-1
的二进制补码表示:
32-bit int: 01111111111111111111111111111111
16-bit short: ----------------1111111111111111
然而,2补码表示法以及这种行为一般都不是C ++标准的一部分,因此这种行为是实现定义的。
当将一个值转换为一个有符号类型时,如果源值无法适应目标类型,则会产生实现定义的结果。这意味着任何符合规范的编译器文档必须记录该结果是什么。
(这与算术运算符溢出的行为不同。例如:
int overflow = INT_MAX + 1;
实际上具有未定义的行为。但无论哪种情况,您都应该注意编写代码以避免触发此类问题。
对于许多实现,无论是转换还是算术,当目标是N位类型时,溢出仅取正确结果的N个低位。
在您的情况下,显然int
是32位而short
是16位(这些大小在不同的实现中可能会有所变化)。2147483647
是0x7fffffff
,其低16位是0xffff
,这是(再次强调,在您的实现中)类型short
中表示-1
的方法。
对于转换为无符号类型,结果由标准严格定义;它获取结果的低N位。对于溢出的浮点转换(例如,将非常大的double
值转换为float
),行为是未定义的。
到目前为止,C和C++的情况都一样。但是,从1999年标准开始,允许溢出的有符号转换引发实现定义的信号。C ++没有这个。我不知道任何一个实际执行此操作的编译器。
我希望看到一些值,而不是
-1
。
-1
就是“一些值”。您有某些特定的值预期吗?
附带说明:
short b = (short)a;
不必要进行强制类型转换。赋值、初始化、参数传递以及 return
语句可以在任何数值类型之间进行赋值,无需进行强制类型转换。该值会被隐式转换:
short b = a;
这是“实现定义行为”,例如,gcc
的整数实现文档
表示:
将值转换为宽度为N的类型时,该值会模2^N对类型范围取模;不会引发信号。
这可能因编译器而异,我找不到类似的clang
或visual studio
文档。
根据草案C++标准,第4.7
节“整数转换”第3
段:
如果目标类型是有符号的,则如果它可以用目标类型(和位域宽度)表示,则该值保持不变;否则,该值是实现定义的。
如果这是无符号的,那么你将拥有完全定义良好的行为,如第2
段所述:
如果目标类型是无符号的,则结果值是源整数的最小无符号整数(模2n,其中n是用于表示无符号类型的位数)。[注意:在二补码表示中,此转换是概念上的,如果没有截断,位模式不会改变。—end note]
草案C99标准的6.3.1.3
节“有符号和无符号整数”的语言类似。
您的整数A比short类型的大小还要大。当您将A转换为short类型时,最左边的一位会变成1,这表示它是一个负数。因此,如果您得到-1,我猜您在所有16位中都得到了1,这将使您得到-2^15 + 2^14 + 2^13... + 2^0,这将使您得到-1。简而言之(无意冒犯),如果整数太大,则无法将其转换为short类型。
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
。
-1
是 "某个值"。而(short)
强制转换是不必要的,转换会被隐式执行:short b = a;
- Keith Thompson