VC ++ 6.0中的调试与发布行为之谜

时间:2015-07-01 00:33:20

标签: 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 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;
}

1 个答案:

答案 0 :(得分:2)

  

(更正先前评论的更正):VC6 ++ SP6中的类似结果,   但我根本得不到“积极”的输出。我要去看看。   我们会看看能不能找到任何东西。没有承诺(Euro Micelli)

我已经复制了相同的结果(发布时根本没有ouptut)@EuroMicelli发现。但是,如果您将 //import not included public class CustomGrid extends BaseAdapter{ private Context mContext; private final String[] web; private final int[] Imageid; public CustomGrid(Context c,String[] web,int[] Imageid ) { mContext = c; this.Imageid = Imageid; this.web = web; } @Override public int getCount() { // TODO Auto-generated method stub return web.length; } @Override public Object getItem(int position) { // TODO Auto-generated method stub return null; } @Override public long getItemId(int position) { // TODO Auto-generated method stub return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { // TODO Auto-generated method stub View grid; LayoutInflater inflater = (LayoutInflater) mContext .getSystemService(Context.LAYOUT_INFLATER_SERVICE); if (convertView == null) { grid = new View(mContext); grid = inflater.inflate(R.layout.grid_single, null); EditText textView = (EditText) grid.findViewById(R.id.grid_text); ImageView imageView = (ImageView)grid.findViewById(R.id.grid_image); // Button b1=(Button)grid.findViewById(R.id.button1); textView.setText(web[position]); imageView.setImageResource(Imageid[position]); } else { grid = (View) convertView; } return grid; } } 声明为volatile,则会显示输出:

RecordCountNew

有关您的信息,volatile是一个关键字,它告诉编译器可以在随机时间(例如在CPU中断期间)从外部修改变量,并防止编译器积极优化其周围的代码。

tldr volatile int RecordCountNew = 0; 错误地优化了MSVC6

PS:将RecordCountNew声明为RecordCountNew而非short会使打印输出重新出现。你永远不知道一个20岁的编译器的大脑里发生了什么。

PPS:因为我被要求解释这个错误,这里是正确输出的反汇编版本:

enter image description here

int寄存器存储edi值,RecordCountNew指令命令跳转到test。但是,这是OP的编译版本:

enter image description here

printf条件正在基指针寄存器test上完成,它与ebp无关。根据{{​​1}}的值,程序每次输出行,或从不输出。