程序在在线IDE上表现奇怪
Program behaving strangely on online IDEs
我遇到了以下C 程序(来源(:
#include <iostream>
int main()
{
for (int i = 0; i < 300; i++)
std::cout << i << " " << i * 12345678 << std::endl;
}
它看起来像一个简单的程序,并在我的本地计算机上给出了正确的输出,例如:
0 0
1 12345678
2 24691356
...
297 -628300930
298 -615955252
299 -603609574
但是,在诸如Codechef之类的在线IDE上,它给出以下输出:
0 0
1 12345678
2 24691356
...
4167 -95167326
4168 -82821648
4169 -7047597
为什么for
循环不在300处终止?同样,该程序总是在4169
上终止。为什么4169
而不是其他值?
我将假设在线编译器使用GCC或兼容编译器。当然,任何其他编译器也可以进行相同的优化,但是GCC文档很好地解释了它的作用:
-faggressive-loop-optimizations
此选项告诉循环优化器使用语言约束来得出循环迭代次数的界限。这是假设循环代码不会通过例如引起签名的整数溢出或界外数组访问来调用未定义的行为。循环迭代次数的边界用于指导循环展开,剥离和循环退出测试优化。默认情况下启用此选项。
此选项仅允许根据证明UB的情况进行假设。要利用这些假设,可能需要启用其他优化,例如恒定折叠。
签名的整数溢出具有未定义的行为。优化器能够证明i
的任何值大于173都会导致UB,并且由于它可以假定没有UB,因此它也可以假设i
永远不会大于173。它可以进一步证明i < 300
始终是是的,因此可以优化循环条件。
为什么4169而不是其他值?
这些站点可能会限制它们显示并恰好共享相同限制的输出线的数量(或字符或字节(。
"未定义的行为是未定义的。" (c(
CodeChef上使用的编译器似乎使用以下逻辑:
- 不确定的行为不会发生。
-
i * 12345678
如果i > 173
(假设32位int
s(。 - 因此,
i
永远无法超过173
。 - 因此,
i < 300
是多余的,可以用true
代替。
循环本身似乎是无限的。显然,CodeChef只是在特定时间之后停止程序或截断输出。
您正在调用for
循环内部第174次迭代的未定义行为,因为最大int
值可能是2147483647
,但174 * 123456789
表达式评估对2148147972
,这是不确定的行为,该行为没有签名的Integer溢出。因此,您正在观察UB的效果,尤其是使用GCC编译器,并在您的情况下设置了优化标志。编译器可能会通过发出以下警告来警告您:
warning: iteration 174 invokes undefined behavior [-Waggressive-loop-optimizations]
删除(-O2
(优化标志以观察不同的结果。
编译器可以假定不会发生未定义的行为,并且由于签名的溢出为UB,因此可以假设从不i * 12345678 > INT_MAX
,因此也可以i <= INT_MAX / 12345678 < 300
,因此也可以删除检查i < 300
。
- 在线编译器中的分段C++没有打印消息
- C++:如何在CLion IDE中安装Boost
- IDE (CLion) 无法解析C++模板类型
- 在线程之间拆分任务总是值得的吗?
- join() 失败,如果在线程内部调用 io_context.run()
- 如何在C++中在线组装?
- 在线程中读取无符号整数时,c++ 位是否以原子方式切换?
- macOS 是内置在 clang 编译器中还是内置于 xcode ide 中?
- 为什么联机C++ IDE 不支持"graphics.h"头文件?
- 在线程函数中处理数据向量时进行线程竞速
- 我应该在线程上调用 processEvents() 吗?
- 如何创建始终在线的过程?
- pthread只有在线程数量较少时才可以正常工作
- Arduino IDE 中使用 strncmp 函数时出错
- boost::asio::io_service 在线程中,不会在应用程序退出时退出
- 如何在线程中初始化对象,然后在其他地方使用它?
- 为什么以下代码在在线 ide(gcc 7.2.0) 上有效,但在 ubuntu 上出现错误?
- 为什么这个C++程序在代码::块和在线 IDE 之间返回不同的结果?
- 程序在在线IDE上表现奇怪
- 为什么它在不同的 IDE 中有不同的行为在线或不在线