VC++ 6.0 中的调试与发布行为之谜
Debug vs Release behavior mystery in VC++ 6.0
对于下面的程序,根据 运行 在 Windows 上 VC++ 6.0 中处于 Debug 模式还是 Release 模式,我会得到不同的结果 7. Debug 的差异和 Release 行为几乎总是表明在处理指针和循环时存在错误,但我无法发现错误。
在调试模式下,我得到了预期的结果:
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;
}
(Correction replacing prior comment): Similar results in VC6++ SP6,
but I get no "is positive" output at all. I'm going to take a look.
We'll see if I can find anything. No promises ( Euro Micelli )
我已经复制了相同的结果(发布时根本没有输出)@EuroMicelli 找到了。但是,如果您将 RecordCountNew
声明为易变的,则输出会出现:
volatile int RecordCountNew = 0;
供您参考,volatile 是一个关键字,它告诉编译器变量可以在外部随机修改(例如在 CPU 中断期间)并防止编译器积极优化周围的代码.
tldr:MSVC6
错误地优化了 RecordCountNew
。
PS :将 RecordCountNew
声明为 short
而不是 int
使打印输出重新出现。你永远不知道 20 岁编译器的大脑里在想什么。
PPS : 因为我被要求解释错误,这里是正确输出的反汇编版本 :
edi
寄存器存储 RecordCountNew
值,test
指令命令跳转到 printf
。但是,这是 OP 的编译版本:
test
条件是在基指针寄存器ebp
上完成的,与RecordCountNew
无关。根据 ebp
的值,程序每次都输出该行,或者从不输出。
对于下面的程序,根据 运行 在 Windows 上 VC++ 6.0 中处于 Debug 模式还是 Release 模式,我会得到不同的结果 7. Debug 的差异和 Release 行为几乎总是表明在处理指针和循环时存在错误,但我无法发现错误。
在调试模式下,我得到了预期的结果:
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;
}
(Correction replacing prior comment): Similar results in VC6++ SP6, but I get no "is positive" output at all. I'm going to take a look. We'll see if I can find anything. No promises ( Euro Micelli )
我已经复制了相同的结果(发布时根本没有输出)@EuroMicelli 找到了。但是,如果您将 RecordCountNew
声明为易变的,则输出会出现:
volatile int RecordCountNew = 0;
供您参考,volatile 是一个关键字,它告诉编译器变量可以在外部随机修改(例如在 CPU 中断期间)并防止编译器积极优化周围的代码.
tldr:MSVC6
错误地优化了 RecordCountNew
。
PS :将 RecordCountNew
声明为 short
而不是 int
使打印输出重新出现。你永远不知道 20 岁编译器的大脑里在想什么。
PPS : 因为我被要求解释错误,这里是正确输出的反汇编版本 :
edi
寄存器存储 RecordCountNew
值,test
指令命令跳转到 printf
。但是,这是 OP 的编译版本:
test
条件是在基指针寄存器ebp
上完成的,与RecordCountNew
无关。根据 ebp
的值,程序每次都输出该行,或者从不输出。