Nem*_*emo 26 c++ language-lawyer c++11
在另一个问题,主题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";
}
Run Code Online (Sandbox Code Playgroud)
当我用g++ -O3 -std=c++11(x86_64 GCC 4.7.2)编译它时,它产生以下输出:
1 -2147483648 1
Run Code Online (Sandbox Code Playgroud)
也就是说,is_modulo是的,一个加号INT_MAX是负数,一个加号INT_MAX大于INT_MAX.
如果你是那种有实际机会回答这个问题的人,你已经知道这里发生了什么.C++规范说整数溢出是Undefined Behavior; 允许编译器假设你不这样做; 因此争论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即使签订算术肯定不会环绕.
是标准车吗?海湾合作委员会不符合规定吗?我错过了什么吗?
eca*_*mur 18
如果is_modulo是true对于有符号的类型(例如int),是由通常的算术转换不变,则用于通过零比除法以外的任何算术运算有一个单一的正确结果,在所述范围内模映射到一个单一的值的(数学)整数类型的,因此实现被约束为表现为好像实际结果是以模型的范围为模的真实结果.因此,如果实现想要将溢出算法保留为未定义,则必须将其设置is_modulo为false.
这是讨论令人作呕 gcc的邮件列表,然后根据PR 22200与最终结论的价值is_modulo应该是false有符号的类型; 今年4月对libstdc ++进行了更改.
请注意,在C++ 03中,语言明显不同:
18.2.1.2 numeric_limits成员[lib.numeric.limits.members]56 - [...]如果可以添加两个正数并且结果包含到较小的第三个数字,则类型是模数.
鉴于与未定义行为什么是可能的,这是有争议的(具有的libstdc ++以前的行为is_modulo是true)是正确的,并与G ++的行为是一致的; 关于相关PR的早期讨论应该考虑到这一点.
| 归档时间: |
|
| 查看次数: |
584 次 |
| 最近记录: |