当二元运算符两侧的符号不同时,提升规则如何工作?
考虑以下程序:
// http://ideone.com/4I0dT
#include <limits>
#include <iostream>
int main()
{
int max = std::numeric_limits<int>::max();
unsigned int one = 1;
unsigned int result = max + one;
std::cout << result;
}
+ 运算符如何
// http://ideone.com/UBuFZ
#include <limits>
#include <iostream>
int main()
{
unsigned int us = 42;
int neg = -43;
int result = us + neg;
std::cout << result;
}
“知道”返回正确的类型?一般规则是将所有参数转换为最宽的类型,但这里 int 和 unsigned int 之间没有明显的“赢家”。在第一种情况下,必须选择 unsigned int
作为 operator+
的结果,因为我得到的结果是 2147483648
。在第二种情况下,它必须选择int
,因为我得到的结果是-1
。但我不知道在一般情况下这是如何确定的。这是我看到的未定义行为还是其他什么?
Consider the following programs:
// http://ideone.com/4I0dT
#include <limits>
#include <iostream>
int main()
{
int max = std::numeric_limits<int>::max();
unsigned int one = 1;
unsigned int result = max + one;
std::cout << result;
}
and
// http://ideone.com/UBuFZ
#include <limits>
#include <iostream>
int main()
{
unsigned int us = 42;
int neg = -43;
int result = us + neg;
std::cout << result;
}
How does the + operator "know" which is the correct type to return? The general rule is to convert all of the arguments to the widest type, but here there's no clear "winner" between int
and unsigned int
. In the first case, unsigned int
must be being chosen as the result of operator+
, because I get a result of 2147483648
. In the second case, it must be choosing int
, because I get a result of -1
. Yet I don't see in the general case how this is decidable. Is this undefined behavior I'm seeing or something else?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
发布评论
评论(3)
在 C 标准化之前,编译器之间存在差异——一些编译器遵循“值保留”规则,而另一些则遵循“符号保留”规则。符号保留意味着如果任一操作数是无符号的,则结果也是无符号的。这很简单,但有时会产生相当令人惊讶的结果(特别是当负数转换为无符号数时)。
C 对相当复杂的“保值”规则进行了标准化。在保值规则下,提升可以/确实取决于类型的实际范围,因此您可以在不同的编译器上得到不同的结果。例如,在大多数 MS-DOS 编译器上,int
与 short
大小相同,而 long
则两者不同。在许多当前系统上,int
的大小与 long
相同,而 short
则两者不同。通过保值规则,这可能会导致两者之间的提升类型不同。
值保留规则的基本思想是,如果可以表示较小类型的所有值,它将提升为更大的有符号类型。例如,16 位 unsigned Short
可以提升为 32 位 signed int
,因为 unsigned Short
的每个可能值都可以表示为signed int
。当且仅当有必要保留较小类型的值时(例如,如果unsigned Short
和signed int
都是16位,这些类型才会被提升为无符号类型,那么 signed int
无法表示 unsignedshort
的所有可能值,因此 unsignedshort
将提升为 unsignedint )。
当您按原样分配结果时,结果无论如何都会转换为目标类型,因此大多数情况下的差异相对较小 - 至少在大多数典型情况下,它只是将位复制到结果中,并且由您决定是否将其解释为已签名或未签名。
当您不分配结果(例如在比较中)时,事情可能会变得非常难看。例如:
unsigned int a = 5;
signed int b = -5;
if (a > b)
printf("Of course");
else
printf("What!");
在符号保留规则下,b
将提升为无符号,并在此过程中变得等于 UINT_MAX - 4
,因此“What!”将采用 if
的一段。通过值保留规则,您可以设法产生一些类似于这样的奇怪结果,但是1)主要在类DOS系统上,其中int
大小相同作为short
,并且2)无论如何通常都更难做到。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
§5/9 中明确概述了这一点:
在这两种情况下,
operator+
的结果是未签名
。因此,第二种情况是有效的:因为在这种情况下,
us + neg
的值不能用int
表示,所以result
的值为实现定义 – §4.7/3:This is outlined explicitly in §5/9:
In both of your scenarios, the result of
operator+
isunsigned
. Consequently, the second scenario is effectively:Because in this case the value of
us + neg
is not representable byint
, the value ofresult
is implementation-defined – §4.7/3: