C++ 是数值_极限<;int>;::_模在逻辑上是矛盾的吗?

C++ 是数值_极限<;int>;::_模在逻辑上是矛盾的吗?,c++,c++11,language-lawyer,C++,C++11,Language Lawyer,年,《标准:数值限制:是模》的主题出现了。但是我想得越多,就越觉得这个规范或者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();

年,《标准:数值限制:是模》的主题出现了。但是我想得越多,就越觉得这个规范或者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";
}
也就是说,
是模
是真的,一加
INT\u MAX
是负的,一加
INT\u MAX
大于
INT\u MAX

如果你是那种有机会回答这个问题的人,你已经知道这里发生了什么。C++规范说明整数溢出是未定义的行为;编译器可以假定您没有这样做;因此,
x+1
的参数不能是
INT_MAX
;因此,编译器可以(并且将)编译
test
函数以无条件返回
true
。到目前为止,一切顺利

但是,报告还指出(18.3.2.4第60-61段):

静态constexpr是_模

如果类型为模,则为True。222对于任何操作,类型为模如果 涉及
+
-
*
对其结果将 如果超出范围
[min(),max()]
,则返回的值不同 从真值减去
max()-min()+1的整数倍

在大多数机器上,对于浮动类型,这是
false
,对于浮动类型,这是
true
无符号整数,
true
表示有符号整数

请注意,第5节第(4)段仍为“如果在表达式求值过程中,结果未在数学上定义或不在其类型的可表示值范围内,则行为未定义。”未提及创建异常的
is_modulo==true

所以在我看来,这个标准在逻辑上是矛盾的,因为整数溢出不能同时定义和不定义。或者至少,GCC是不一致的,因为它具有
is_modulo
as
true
,即使有符号算术肯定不会结束


是标准的手推车吗?GCC是否不符合要求?我遗漏了什么吗?

如果有符号类型(例如,
int
)的
is_modulo
true
,但通常的算术转换没有改变,那么对于除零除之外的任何算术运算,(数学)中只有一个正确的结果模映射到类型范围内单个值的整数,因此实现的行为受到约束,就好像实际结果是模类型范围内的真实结果一样。因此,如果一个实现想要保留未定义的溢出算法,它必须将
is_modulo
设置为
false

这在gcc邮件列表上进行了令人厌恶的讨论,然后在下面进行了讨论,最终得出结论:对于签名类型,
的值为_modulo
应为
false
;已于今年4月提交给libstdc++

请注意,在C++03中,语言明显不同:

18.2.1.2数值限制成员[lib.numeric.limits.members] 56-[…]如果可以将两个正数相加,并且结果为 环绕到第三个较小的数字


考虑到对于未定义的行为,任何事情都是可能的,因此有争议的是libstdc++(具有
is_modulo
作为
true
)之前的行为是正确的,并且与g++的行为一致;阅读之前关于链接PR的讨论时,应牢记这一点。

虽然我对它同时定义和未定义感到不安,但gcc在我看来是一致的:
max()+1==min()
@BoBTFish,那么这种一致性如何
max()+1==min()
min()>max()
?我认为已定义/未定义的问题是一个危险的问题。该语言不需要溢出来定义行为,但是如果实现想要定义行为,它可以自由地这样做,当它以特定的方式这样做时,它会告诉您这一点。@JerryCoffin:好的,但是当GCC说
is_modulo
为true时,这不意味着行为已经定义好了吗,因此,在这种情况下禁止优化?@Nemo:我想现在我必须阅读你之前的问题,以了解你在说什么优化……是的,我也应该提到C++03规范。谢谢大家,;PR22200正是我想要的那种东西。(也很高兴知道它是固定的。我对我能找到的最新的GCC进行了第一次测试,在Ubuntu上是4.7.2。)为了澄清,我们说结果
1-2147483648 1
在C++11中肯定有错误(但在C++03中没有),并且
is_modulo==true
意味着溢出行为没有未定义?@MattMcNabb:Yes,根据GCC开发人员的说法,其结果可以说是在C++03中存在缺陷(尽管这是有争议的),并且在C++11中肯定存在缺陷。由于这个原因,较新的GCCs集
是_modulo
false
。在他们(和我的)看来,
is_modulo==true
意味着定义了溢出并将其环绕在la
-fwrapv
上。我不知道其他编译器做什么。
1 -2147483648 1