程序没有按顺序通过构造函数,从而导致未初始化的变量

Posted

技术标签:

【中文标题】程序没有按顺序通过构造函数,从而导致未初始化的变量【英文标题】:Program does not go in order through constructor thus leading to uninitialized variables 【发布时间】:2015-05-13 03:11:11 【问题描述】:

在尝试使用 Qt 5.4 使用 MSVC 2013 32 位在发布模式下编译我的程序后,我发现了这个问题。到目前为止,在调试中一切正常,但是每次尝试在发行版中运行它时都会抛出错误代码:0xc0000409。看起来这通常意味着某处存在初始化变量,因此我通过代码设置断点以查看问题所在。我发现在我的一个类的构造函数中,如果我在每一行上设置一个断点,它会从中间的某个地方开始,并跳过我为该对象初始化变量的位置。代码如下:

#ifndef AD5932DDS_H
#define AD5932DDS_H

#include "adicyusbusb4.h"
#include <QObject>
#include "picosignal.h"
#include <QLibrary>


class AD5932DDS : public QObject

Q_OBJECT
public:
    AD5932DDS(QObject *parent = 0);
    ~AD5932DDS();

private:
    QLibrary *myLib;

    unsigned int handle;

    VendorRequestFunction Vendor_Request;
    DisconnectFunction Disconnect;
    SearchFunction Search_For_Boards;
    ConnectFunction Connect;
    DownloadFWFunction Download_Firmware;

;


#endif // AD5932DDS_H




AD5932DDS::AD5932DDS(QObject *parent) : QObject(parent)

int searchErrorCode = 0;
int connectErrorCode = 0;
int downloadErrorCode = 0;
unsigned int num_boards = 0;
handle = 0;

char pcFilePath[] = "C:\\Users\\Jason\\Documents\\Development\\Qt\\CrackDetection\\AD593x.hex";
char path = 0;
myLib = new QLibrary;
myLib->setFileName("ADI_CYUSB_USB4.dll");
Search_For_Boards = (SearchFunction) myLib->resolve("Search_For_Boards");
Connect = (ConnectFunction) myLib->resolve("Connect");
Download_Firmware = (DownloadFWFunction) myLib->resolve("Download_Firmware");
Vendor_Request = (VendorRequestFunction) myLib->resolve("Vendor_Request");
Disconnect = (DisconnectFunction) myLib->resolve("Disconnect");
if (!Search_For_Boards || !Connect || !Download_Firmware || !Vendor_Request || !Disconnect)

    myLib->unload();


searchErrorCode = Search_For_Boards(VID, PID, &num_boards, &path);

if (num_boards > 0)

    connectErrorCode = Connect(VID, PID, path, &handle);
    if (connectErrorCode == 0)
    
        downloadErrorCode = Download_Firmware(handle, pcFilePath2);
    


如果我逐步调试这些版本,它中断的第一行是上面的行

char pcFilePath[] = "C:\\Users\\Jason\\Documents\\Development\\Qt\\CrackDetection\\AD593x.hex";

然后它会回到顶部并正常继续下降,一切正常。

但是,如果我把

QMAKE_CXXFLAGS_RELEASE = $$QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO
QMAKE_LFLAGS_RELEASE = $$QMAKE_LFLAGS_RELEASE_WITH_DEBUGINFO

在 .pro 文件中允许在调试发布版本时设置断点,要命中的第一个断点是

handle = 0;

从这里开始向下,跳过上面的初始化,以便

myLib = new QLibrary;
myLib->setFileName("ADI_CYUSB_USB4.dll");

在继续前两次击中这两个位置。我注意到的一件事是,即使在

Search_For_Boards = (SearchFunction) myLib->resolve("Search_For_Boards");
Connect = (ConnectFunction) myLib->resolve("Connect");
Download_Firmware = (DownloadFWFunction) myLib->resolve("Download_Firmware");
Vendor_Request = (VendorRequestFunction) myLib->resolve("Vendor_Request");
Disconnect = (DisconnectFunction) myLib->resolve("Disconnect");

运行时,如果我检查这些名称和值,则这些列表中的每一个都在值下。所以这让我觉得也许每个问题都源于尝试访问这个 dll。

dll 来自这里https://ez.analog.com/thread/11089,经过多次试验和错误,我能够弄清楚如何在没有提供静态库或带有原型的头文件的情况下使用 dll。我所做的是在这样的头文件中创建自己的原型:

#ifndef ADICYUSBUSB4_H
#define ADICYUSBUSB4_H

const unsigned int VID = 0x0456;
//const unsigned int PID = 0xB20B; // EVAL-AD5932EBZ
const unsigned int PID = 0xB205; // EVAL-AD5930EBZ
const unsigned char WRITE = 0xDD;
const unsigned char SET_STANDBY_PIN = 0xDC;
const unsigned char CLEAR_STANDBY_PIN = 0xDB;
const unsigned char PULSE_CONTROL_PIN = 0xDA;
const unsigned char SET_CONTROL_PIN = 0xD9;
const unsigned char CLEAR_CONTROL_PIN = 0xD8;
const unsigned char PULSE_INTERRUPT_PIN = 0xD7;


typedef unsigned int (*SearchFunction) (unsigned int, unsigned int, unsigned int *, char *);
typedef int (*ConnectFunction) (unsigned int, unsigned int, char, unsigned int *);
typedef int (*DownloadFWFunction) (unsigned int, char []);
typedef int (*VendorRequestFunction) (unsigned int, unsigned char, unsigned short, unsigned short, unsigned char, unsigned short, unsigned char *[]);
typedef int (*DisconnectFunction) (unsigned int);

#endif // ADICYUSBUSB4_H 

这种方法在调试模式下效果很好,但有些东西不适合发布。

所以要么我不正确地处理这个 dll(尽管它在调试模式下工作得很好),要么我的程序由于某种未知原因跳过了一些变量初始化。

【问题讨论】:

int searchErrorCode = 0; int connectErrorCode = 0; int downloadErrorCode = 0; unsigned int num_boards = 0; 不是成员变量的初始化,而只是局部定义。你确定那是你想要的吗?如果您有成员变量,例如searchErrorCode,那么你的构造函数定义最终会遮蔽它们。 我只在构造函数中使用这些变量。 Handle 是我在其他地方使用的唯一变量。 【参考方案1】:

在启用优化的情况下编译时不要依赖断点或单步执行。优化器将更改、重新排序或删除语句。不要花太多时间尝试分析经过优化编译的程序的流程。

QLibrary 是否以某种方式失败?检查isLoaded() 并记录各种resolve() 调用的返回值。如果发生故障,您正在调用unload(),但您正在愉快地执行其余的操作,尝试取消引用空指针。

您能准确说出崩溃的位置吗?尝试使用无缓冲流在每个语句之间向控制台输出一些内容,例如std::cerr

这可能与您的工作目录不同并且 DLL 无法加载一样愚蠢。

【讨论】:

【参考方案2】:

我相信 0xc0000409 表示堆栈损坏,这可能是由各种原因造成的,而不仅仅是未初始化的变量。

由于您注意到您必须手动创建 DLL 标头,因此它可能与 DLL 的实际实现方式不完全匹配。除了参数计数/类型和返回类型之外,还有调用约定。由于您没有指定一个,您将获得 MSVC 的默认值。但是,如果该 DLL 是用选择不同约定的东西编译的,那么这种不匹配就会导致问题。

事实上,一个可能的结果是堆栈损坏。我不能肯定这是您的问题,但我相信这与您的 0xc0000409 错误一致。

理想情况下,该 DLL 的提供者能够提供正确的信息。 (或者至少,如果你能找出他们使用的编译器,那么你可以研究它的默认调用约定。)

但如果他们不能或不会,那么您可能不得不尝试不同的方法并查看哪些似乎可以正常工作。

【讨论】:

如果它在我的调试版本中工作会是这种情况吗? 我刚刚发现的一个可能的问题是,他们列出的函数原型与我所拥有的略有不同。例如他们网站上的Uint Search_For_Boards (uint VID, uint PID, uint *Num_boards, char *PartPath[]); 和我使用的typedef unsigned int (*SearchFunction) (unsigned int, unsigned int, unsigned int *, char *);。我已经尝试让我的原型中的参数 4 与他们的匹配,但我似乎无法让它发挥作用。我如何通过引用为这个传递声明一个变量? 我不相信。今天早上花了 2 1/2 小时来愚弄我在上面评论中提到的内容后,我决定回到调试模式下工作的内容。然后,我将 __stdcall 添加到我的函数原型中,例如 typedef unsigned int (__stdcall *SearchFunction) (unsigned int, unsigned int, unsigned int *, char *);,现在一切正常。那么为什么在没有这个调用约定的调试模式下一切都很好,但在发布时却不起作用? 副手我不知道为什么调试似乎工作。我想编译器可能会在调试模式下假设不同的默认值,但我没想到会这样。否则,也许它仍在破坏堆栈,但还不足以触发异常。调试和发布模式会做很多不同的事情,因此不同的内存布局最终会有所不同。所以也许只有一些“无害”的字节被破坏了。【参考方案3】:

您正在构造函数中声明变量。构造函数仅用于初始化变量,因此请尝试更改它(在构造函数中声明没有任何作用,尤其是默认值)

【讨论】:

变量是本地使用的,所以当然有它们是有意义的 问题:为什么在写路径名的时候有2个'\'?是另一种写法吗? @frank。对不起,我错过了

以上是关于程序没有按顺序通过构造函数,从而导致未初始化的变量的主要内容,如果未能解决你的问题,请参考以下文章

类与对象动手动脑

java中静态方法,静态变量,静态初始化器,构造函数,属性初始化都是啥时候调用的? 它们的先后顺序。

java 静态代码块 代码块 构造函数 静态成员变量 成员变量的初始化顺序

Symfony 2,未定义的变量,在构造函数中初始化为 ArrayCollection 的受保护成员通过错误,它是未定义的

实例构造函数与静态构造函数执行顺序

JavaScript 变量和函数提升问题总结