0

我在将 C++ Builder 6 项目升级到 C++ Builder XE3 时遇到问题。目前我的问题是:在发布模式下编译和运行时,项目抛出“特权指令”。我已经追踪到围绕 strcpy() 调用的两个不同 for 循环的错误。我尝试将其更改为 strncpy() 并包括字符串大小,但无济于事。我所知道的是,当我注释掉这两行时,错误就消失了。

相关代码:

/** Main.h */
class TForm1 : public TForm {
    published:
        void __fastcall ReadCalFromUnitBtnClick(TObject *Sender);
    private:
        struct CALIBRATION {
            char name[64];
            float gain1;
            float gain2;
            float offset;
            ...
            ... // A few more values that aren't pertinent to this question.
        };
        CALIBRATION calibr[256];
        void __fastcall TForm1::ReadCalibrationFromUnit(CALIBRATION *reg);
};
extern char *ADC_names[];

/** Main.cpp */
char *ADC_names[] = {
    "String 1",
    "String 2",
    "String 3",
    "String 4",
    "String 5",
    "String 6",
    "String 7",
    "String 8"
};

void __fastcall TForm1::ReadCalFromUnitBtnClick(TObject *Sender) {
    memset(calibr,0,sizeof(calibr));
    ReadCalibrationFromUnit(calibr);
}    

void __fastcall TForm1::ReadCalibrationFromUnit(CALIBRATION *reg) {

    // for (int j=0, j < 8, j++) { // Incorrect; but no bearing on actual soln.

    for (int j=0; j < 8; j++) {
        // Here's the problematic line. Another loop exists which does the same
        //   thing for another 18 array members in reg, but is essentially 
        //   identical to this one.
        strcpy(reg[j].name, ADC_names[j]); 
    }
}

我已经尝试了很多事情,例如使 ADC_names 成为 const char,省略外部声明,尝试将 strncpy() 放入 reg[] 数组...

据我所知,所有内存都已正确分配以解决所有问题,ADC_names[]远非空,因为我们甚至在进入表单构造函数之前就定义了它。尝试calibr[]直接在 for 循环中编辑,而不是reg它传递到的函数变量,但错误仍然存​​在。

真正奇怪的是,这个错误只在我在发布模式下编译和运行时出现。调试根本不会给出这个错误。

随着程序执行的进行,错误也会发生变化。“特权错误”仅在通过单击自动连接按钮调用该函数时在启动时显示。稍后,当手动单击该按钮时,错误变为“地址 00000000 的访问冲突。读取地址 00000000”。

我已经尝试过解决这个问题,但是由于我对内存处理的了解有限,一切似乎都还不错。知道是什么原因造成的吗?

谢谢。-丹尼尔

4

2 回答 2

1

当您在此处发布代码时,可能只是复制和粘贴错误,但是您是否意识到您的 for 循环是“错误的”?

for (int j=0, j < 8, j++)

应该

for (int j=0; j < 8; j++)

对 ?想知道,为什么你不会得到一个编译器错误,但我不熟悉 C++ builder 的编译器......

于 2013-09-09T18:01:26.980 回答
0

这是通过研究@UlrichEckhardt 的评论来解决的:

也许这是经典的“静态初始化顺序惨败”的一种形式?

原来memset(calibr,0,sizeof(calibr))执行的时间比函数调用要长ReadCalibrationFromUnit(calibr);。正式地,这个“静态初始化顺序惨败”表明你有 50/50 的机会让程序做对了。但是,就我而言,这个问题每次都会发生。

为了修复它,我只是将代码从ReadCalibrationFromUnit()函数移回ReadCalFromUnitBtnClick()事件中,因为这个事件是唯一调用第二个函数的东西,使得第二个函数的存在变得多余和不必要。

所以现在我的代码出现了:

/** Main.cpp */
char *ADC_names[] = {
   "String 1",
    "String 2",
    "String 3",
    "String 4",
    "String 5",
    "String 6",
    "String 7",
    "String 8"
};

void __fastcall TForm1::ReadCalFromUnitBtnClick(TObject *Sender) {
    memset(calibr, 0, sizeof(calibr));
    for (int j = 0; j < 8; j++) {
        strcpy(calibr[j].name, ADC_names[j]);
    }
}
于 2013-09-10T16:04:49.633 回答