在另一个问题中,出现了话题std::numeric_limits<int>::is_modulo
。但是我想得越多,规范或 GCC 或两者似乎都有问题。
让我从一些代码开始:
#include <limits>
#include <iostream>
bool test(int x)
{
return x+1 > x;
}
int main(int argc, char *argv[])
{
int big = std::numeric_limits<int>::max();
std::cout << std::numeric_limits<int>::is_modulo << " ";
std::cout << big+1 << " ";
std::cout << test(big) << "\n";
}
当我使用g++ -O3 -std=c++11
(x86_64 GCC 4.7.2) 编译它时,它会产生以下输出:
1 -2147483648 1
即,is_modulo
为真,一加INT_MAX
为负,一INT_MAX
加大于INT_MAX
。
如果您是那种有实际机会回答这个问题的人,那么您已经知道这里发生了什么。C++ 规范说整数溢出是未定义的行为;允许编译器假设您不这样做;因此论点x+1
不能是INT_MAX
;因此编译器可以(并且将)编译该test
函数以true
无条件返回。到目前为止,一切都很好。
但是,C++11 规范也说(18.3.2.4 第 60-61 段):
static constexpr is_modulo;
如果类型为模,则为真。222 如果对于任何涉及
+
、-
或*
对该类型的值的结果超出范围的操作[min(),max()]
,返回的值与真值相差 的整数倍,则该类型为模max() - min() + 1
。在大多数机器上,这
false
适用于浮点类型、true
无符号整数和true
有符号整数。
请注意,第 5 节第 (4) 节仍然写道,“如果在计算表达式期间,结果未在数学上定义或不在其类型的可表示值范围内,则行为未定义。” 没有提到is_modulo == true
创建异常。
所以在我看来,标准在逻辑上是矛盾的,因为整数溢出不能同时定义和未定义。或者至少,GCC 是不符合标准的,因为is_modulo
即使true
有符号算术肯定不会环绕它。
标准的越野车吗?GCC 不合格吗?我错过了什么吗?