C++ VC+中的调试与发布行为之谜+;6

C++ VC+中的调试与发布行为之谜+;6,c++,visual-c++,undefined-behavior,C++,Visual C++,Undefined Behavior,对于下面的程序,我会得到不同的结果,这取决于我是在Windows 7上的VC++6.0中以调试模式还是发布模式运行它。调试和发布行为的差异几乎总是表明在处理指针和循环时存在错误,但我无法发现错误 在调试模式下,我得到了预期的结果: Entered loop with i == 0, RecordCountNew == 0 RecordCountNew = 1 is positive. Entered loop with i == 1, RecordCountNew == 1 Adding rec

对于下面的程序,我会得到不同的结果,这取决于我是在Windows 7上的VC++6.0中以调试模式还是发布模式运行它。调试和发布行为的差异几乎总是表明在处理指针和循环时存在错误,但我无法发现错误

在调试模式下,我得到了预期的结果:

Entered loop with i == 0, RecordCountNew == 0
RecordCountNew = 1 is positive.
Entered loop with i == 1, RecordCountNew == 1
Adding record with i == 1, RecordCountNew == 1
Added record with i == 1, RecordCountNew == 2
RecordCountNew = 3 is positive.
Entered loop with i == 2, RecordCountNew == 3
RecordCountNew = 4 is positive.
Finished loop with i == 3, RecordCountNew == 4
在发布模式下,我得到了相同的结果,除了关于RecordCountNew为正的断言之外:

Entered loop with i == 0, RecordCountNew == 0
RecordCountNew = 1 is positive.
Entered loop with i == 1, RecordCountNew == 1
Adding record with i == 1, RecordCountNew == 1
Added record with i == 1, RecordCountNew == 2
RecordCountNew = 3 is positive.
Entered loop with i == 2, RecordCountNew == 3
Finished loop with i == 3, RecordCountNew == 4
有人能在他们的机器上复制这个吗,或者更好的解释一下

#include <stdio.h>
#include <algorithm>

using namespace std;

struct record {
    int ID;
};

int RecordLimit;
record* Records = NULL;
record** RecordIndex = NULL;
record** RecordIndexNew = NULL;

int main(int argc, char* argv[]) {

    RecordLimit = 10;
    Records = new (nothrow) record[RecordLimit];
    RecordIndex = new (nothrow) record*[RecordLimit];
    RecordIndexNew = new (nothrow) record*[RecordLimit];

    int i;
    for (i = 0; i < RecordLimit; i++) {
        RecordIndex[i] = NULL;
        RecordIndexNew[i] = NULL;
    }

    int RecordCount = 0;
    for (i = 0; i < 3; i++) {
        Records[i].ID = i;
        RecordCount++;
    }

    int RecordCountNew = 0;
    for (i = 0; i < RecordCount; i++) {

        printf("Entered loop with i == %d, RecordCountNew == %d\n", i, RecordCountNew);

        RecordIndexNew[RecordCountNew] = RecordIndex[i];

        bool AddNewRecord = (i == 1);

        if (AddNewRecord) {
            printf("Adding record with i == %d, RecordCountNew == %d\n", i, RecordCountNew);
            Records[RecordCount + (RecordCountNew - i)].ID = RecordCount + (RecordCountNew - i);
            RecordIndexNew[RecordCountNew + 1] = RecordIndexNew[RecordCountNew];
            RecordIndexNew[RecordCountNew] = &Records[RecordCount + (RecordCountNew - i)];
            RecordCountNew++;
            printf("Added record with i == %d, RecordCountNew == %d\n", i, RecordCountNew);
        }

        RecordCountNew++;
        if (RecordCountNew > 0) printf("RecordCountNew == %d is positive.\n", RecordCountNew);
    }

    printf("Finished loop with i == %d, RecordCountNew == %d\n", i, RecordCountNew);

    delete[] Records;
    delete[] RecordIndex;
    delete[] RecordIndexNew;

    return 0;
}
#包括
#包括
使用名称空间std;
结构记录{
int-ID;
};
int记录限制;
记录*记录=NULL;
记录**记录索引=NULL;
记录**RecordIndexNew=NULL;
int main(int argc,char*argv[]){
记录限值=10;
记录=新(nothrow)记录[记录限制];
RecordIndex=新(nothrow)记录*[RecordLimit];
RecordIndexNew=新(nothrow)记录*[RecordLimit];
int i;
对于(i=0;i0)printf(“RecordCountNew==%d为正。\n”,RecordCountNew);
}
printf(“已完成循环,i==%d,RecordCountNew==%d\n”,i,RecordCountNew);
删除[]条记录;
删除[]记录索引;
删除[]RecordIndexNew;
返回0;
}
(更正取代先前的注释):VC6++SP6中的类似结果, 但我没有得到任何“正”输出。我要去看看。 我们看看能不能找到什么。无承诺(欧元i)

我发现,我已经复制了同样的结果(在发布时根本没有ouptut)。但是,如果将
RecordCountNew
声明为volatile,则会出现以下输出:

volatile int RecordCountNew = 0;
请注意,volatile是一个关键字,它告诉编译器可以在随机时间(例如在CPU中断期间)对变量进行外部修改,并防止编译器主动优化其周围的代码

tldr
MSVC6
错误地优化了
RecordCountNew

备注:将
RecordCountNew
声明为
short
而不是
int
会使打印输出重新出现。你永远不知道一个20岁的编译器脑子里在想什么

PPS:既然我被要求解释错误,下面是正确输出的反汇编版本:

edi
寄存器存储
RecordCountNew
值和
test
指令跳转到
printf
。但是,以下是OP的编译版本:


测试
条件是在基本指针寄存器
ebp
上执行的,这与
RecordCountNew
无关。根据
ebp
的值,程序每次都输出一行,或者从不输出。

我不再使用VC 6.0,但在VS2013中不会出现这种情况。你可以试着在发布模式下调试它。你到底为什么仍然使用VC 6.0?我使用Dev-C++进行发布编译,但发现VC++6.0便于调试,并注意到了这个差异。如果VC++6.0中有一个bug,而代码中没有,那么我不必担心,但这就是我来这里要确定的。如果是这样,你的问题就错了。您用于调试的软件与此无关。重要的是编译器。你是说首个版本来自VC6,而发行版来自Dev-C++?不——我是在比较VC++6.0调试模式和VC++6.0发行模式。没有任何理由需要在这个变量上使用volatile。将变量标记为volatile只会阻止编译器对其应用大多数优化,因此这是一种逃避/解决方法。这并没有回答这是一个优化器错误还是UB的问题。@I:这是一个编译器错误。感谢您记录所有的细节;这是很好的解释。这和我昨天看到的一模一样。我担心的是,这并不能证明它是一个优化器错误。如果源代码包含未定义的行为(UB),则允许优化器输出无意义的汇编程序。仅仅通过查看汇编程序的输出,几乎不可能区分优化错误和UB的影响。你要么必须对优化器有深入的了解,要么必须对源代码进行推理并确认它没有UB。尽管如此,我仍然没有发现源代码有任何错误,所以我相信你可能是正确的。我希望有人能解释一下错误是什么。