我有以下代码:
#include <iostream>
#include <complex>
using namespace std;
int main() {
complex<int> delta;
complex<int> mc[4] = {0};
for(int di = 0; di < 4; di++, delta = mc[di]) {
cout << di << endl;
}
return 0;
}
我希望它输出“0,1,2,3”并停止,但它输出的是一系列无穷无尽的“0、1、2、3、4、5……”
看起来比较< code>di
如果我只是注释掉< code >,delta=mc[di],我会正常得到“0,1,2,3”。无辜作业有什么问题?
我正在使用Ideone.com g14带-O2选项。
你有这个:
for(int di=0; di<4; di++, delta=mc[di]) {
cout<<di<<endl;
}
试试这个:
for(int di=0; di<4; delta=mc[di++]) {
cout<<di<<endl;
}
编辑:
为了澄清正在发生的事情,让我们分解一下 For 循环的迭代:
第一次迭代:最初di设置为0。比较检查:di小于4吗?是的,好的,继续。将di增加1。现在di=1。抓取mc[]的“第n个”元素并将其设置为delta。这次我们抓取第二个元素,因为这个索引值是1而不是0。最后执行for循环中的代码块/s。
第二次迭代:现在di设置为1。比较检查:di小于4吗?是的,然后继续。将di增加1。现在di=2。抓取mc[]的“第n”个元素并将其设置为delta。这次我们抓取第三个元素,因为这个索引值是2。最后在for循环中执行代码块/s。
第三次迭代:现在di设置为2。比较检查:di小于4吗?是的,然后继续。将di递增1。现在di=3。抓取mc[]的“nth”元素并将其设置为delta。这次我们抓取第4个元素,因为这个索引值是3。最后执行for循环内的代码块/s。
第 4 次迭代:现在 di 设置为 3。比较检查:di是否小于4?是的,然后继续。Increment di 乘以 1.现在 di = 4.(你能看出这是怎么回事吗?获取 mc[] 的“第 n 个”元素,并将其设置为增量。这次我们抓取第 5 个元素,因为这个索引值为 4。哦,哦,我们有一个问题;我们的数组大小只有 4。Delta现在有垃圾,这是未定义的行为或损坏。最后使用“垃圾增量”在 for 循环内执行代码块。
第 5 次迭代。现在 di 设置为 4。比较检查:di是否小于4?不,打破循环。
超过连续内存(数组)的边界而损坏。
由于您在使用di来索引mc
之前会递增di
,因此第四次通过循环,您将引用mc[4],这已经过了数组的末尾,这反过来可能导致麻烦的行为。
这是由于未定义的行为,您在循环的最后一次迭代中越界访问数组mc
。一些编译器可能会围绕没有未定义行为的假设执行积极的循环优化。逻辑类似于以下内容:
mc
是未定义的行为,我们
打开优化并使用
-fno-激进循环优化
标志的 gcc 会导致无限循环行为消失(实时查看)。虽然一个具有优化但没有-fno-激进循环优化的实时示例展示了您观察到的无限循环行为。
该代码的一个godbolt实时示例显示了
di
jmp .L6
这与 GCC 4.8 之前打破已破损的 SPEC 2006 基准测试中概述的情况几乎完全相同。对本文的评论非常好,非常值得一读。它指出,叮当声在文章中使用
-fsanitize=未定义
捕获了这种情况,在这种情况下我无法重现,但是使用-fsanitize=未定义的
gcc确实如此(请参阅实时)。围绕围绕未定义行为进行推理的优化器最臭名昭着的错误可能是 Linux 内核空指针检查删除。
尽管这是一种激进的优化,但需要注意的是,正如C标准所说,未定义的行为是:
本国际标准没有要求的行为
这基本上意味着一切皆有可能,它指出(强调我的):
[...]允许的未定义行为的范围从完全忽略具有不可预测结果的情况,到在翻译或程序执行期间以环境特有的记录方式表现(发出或不发出诊断消息),到终止翻译或执行(发出诊断消息)。[...]
为了从 gcc 获得警告,我们需要将
cout
移到循环之外,然后我们看到以下警告(实时查看):
warning: iteration 3u invokes undefined behavior [-Waggressive-loop-optimizations]
for(di=0; di<4;di++,delta=mc[di]){ }
^
这可能足以为OP提供足够的信息来弄清楚发生了什么。像这样的不一致是典型的行为类型,我们可以在未定义的行为中看到。为了更好地理解为什么面对未定义的行为时,这种警告可能是不一致的 为什么在基于未定义行为进行优化时不能发出警告?是一本好书。
注意,
-fno aggressive loop optimizations
在gcc 4.8发行说明中有记录。
我正在尝试编译这里提到的桥接模式C示例代码 但是,当我使用g-o桥时,我会遇到编译错误。C 计划: 错误: ]#g-o桥桥。C桥。C: 在成员函数“virtual void TimeImp::tell()”中:Bridge。C: 14:错误:“运算符”不匹配 这是错误的一部分,它以相同的模式扩展。 我复制粘贴了相同的代码,分析了错误行,但无法得到它。 有人能告诉我我哪里错了吗?
我试图用Qt Creator为Android编译一个普通的C++静态库。然而,我收到了这个错误: 我需要包括上述库的路径。 如果有人能给我指明方向,我将不胜感激。
本文向大家介绍C++ 用Clang编译,包括了C++ 用Clang编译的使用技巧和注意事项,需要的朋友参考一下 示例 由于锵前端被设计为是与GCC兼容,当你交换可通过GCC编译大多数程序将编译g++通过clang++在构建脚本。如果没有-std=version给出,将使用gnu11。 习惯了MSVC的Windows用户可以cl.exe与交换clang-cl.exe。默认情况下,clang尝试与已安
问题内容: 在编译C 时,您当然会为要编译的目标平台使用编译器。是否有针对JVM的C 编译器(因此,不是使用Java“本机”接口,而是将C ++代码编译为Java字节码)? 问题答案: NestedVM为Java字节码提供二进制转换。这是通过让GCC编译为MIPS二进制文件然后将其转换为Java类文件来完成的。因此,任何用C,C ++,Fortran或GCC支持的任何其他语言编写的应用程序都可以在
问题内容: 当我在Netbeans中构建并运行程序时,它可以正常工作。但是当我尝试“ mvn compile”时,使用相同的pom.xml文件会出现以下错误: 我的Java版本不是1.3,这里是“ mvn -version”的结果 这是第53行: 问题答案: 问题是在Maven2中默认使用和 您可以通过将其添加到pom中来解决此问题: 将其放在最顶层的父pom中是很实际的,这样您派生的pom不需要
我遇到了一个初学者的编译错误: 我的简单程序: 我尝试使用以下命令编译它: gcc-g-Wall-ansi launch_瓷砖。c-o tiles\u程序 并得到这些错误: 启动_tiles。c: 在函数“main”中: launch_tiles. c: 17:19:错误:预期')'之前';'令牌 launch_tiles. c: 17:19:错误:太少的参数函数'fget' /usr/inclu