在C语言中将int转换为short

13

我有:

int a = 2147483647;
short b = (short)a;

我得到了b = -1,但我期望将int32转换为int16(short)。我希望看到一些值,而不是-1

请有人帮助我解决这个问题。


1
我会说,这个值不适合,所以结果未定义。 - Bart Friederichs
3
-1 "某个值"。而 (short) 强制转换是不必要的,转换会被隐式执行:short b = a; - Keith Thompson
2
@BartFriederichs:转换结果是实现定义,而不是未定义的。 - Keith Thompson
5个回答

26

值2147483647或231-1溢出了16位整数。它的二进制表示在MSB为零,其余位是31个1。

看起来在你的实现中,在转换为short时,取了最后16位。当这种情况发生时,它们全部设置为1,导致了一个-1二进制补码表示:

32-bit int:   01111111111111111111111111111111
16-bit short: ----------------1111111111111111

然而,2补码表示法以及这种行为一般都不是C ++标准的一部分,因此这种行为是实现定义的。


8
行为并非未定义;结果是实现定义的,这意味着实现必须记录它。 - Keith Thompson
2
@EricPostpischil:n3690 第80页4.7(1)说这是实现定义,而不是未定义。但不确定一个实现是否可以将其定义为未定义行为 :-) - 6502

11

当将一个值转换为一个有符号类型时,如果源值无法适应目标类型,则会产生实现定义的结果。这意味着任何符合规范的编译器文档必须记录该结果是什么。

(这与算术运算符溢出的行为不同。例如:

int overflow = INT_MAX + 1;

实际上具有未定义的行为。但无论哪种情况,您都应该注意编写代码以避免触发此类问题。

对于许多实现,无论是转换还是算术,当目标是N位类型时,溢出仅取正确结果的N个低位。

在您的情况下,显然int是32位而short是16位(这些大小在不同的实现中可能会有所变化)。21474836470x7fffffff,其低16位是0xffff,这是(再次强调,在您的实现中)类型short中表示-1的方法。

对于转换为无符号类型,结果由标准严格定义;它获取结果的低N位。对于溢出的浮点转换(例如,将非常大的double值转换为float),行为是未定义的。

到目前为止,C和C++的情况都一样。但是,从1999年标准开始,允许溢出的有符号转换引发实现定义的信号。C ++没有这个。我不知道任何一个实际执行此操作的编译器。

我希望看到一些值,而不是-1

-1就是“一些值”。您有某些特定的值​​预期吗?

附带说明:

short b = (short)a;

不必要进行强制类型转换。赋值、初始化、参数传递以及 return 语句可以在任何数值类型之间进行赋值,无需进行强制类型转换。该值会被隐式转换:

short b = a;

9

这是“实现定义行为”,例如,gcc整数实现文档表示:

将值转换为宽度为N的类型时,该值会模2^N对类型范围取模;不会引发信号。

这可能因编译器而异,我找不到类似的clangvisual studio文档。

根据草案C++标准,第4.7节“整数转换”第3段:

如果目标类型是有符号的,则如果它可以用目标类型(和位域宽度)表示,则该值保持不变;否则,该值是实现定义的。

如果这是无符号的,那么你将拥有完全定义良好的行为,如第2段所述:

如果目标类型是无符号的,则结果值是源整数的最小无符号整数(模2n,其中n是用于表示无符号类型的位数)。[注意:在二补码表示中,此转换是概念上的,如果没有截断,位模式不会改变。—end note]

草案C99标准的6.3.1.3节“有符号和无符号整数”的语言类似。


8

您的整数A比short类型的大小还要大。当您将A转换为short类型时,最左边的一位会变成1,这表示它是一个负数。因此,如果您得到-1,我猜您在所有16位中都得到了1,这将使您得到-2^15 + 2^14 + 2^13... + 2^0,这将使您得到-1。简而言之(无意冒犯),如果整数太大,则无法将其转换为short类型。


4
你可以这样做:
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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接