C++ 是数值_极限<;int>;::_模在逻辑上是矛盾的吗?
年,《标准:数值限制:是模》的主题出现了。但是我想得越多,就越觉得这个规范或者GCC或者两者都有问题 让我从一些代码开始: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();
#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
astrue
,即使有符号算术肯定不会结束
是标准的手推车吗?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