为什么我会有运行时检查失败错误?

问题描述:

我没有意识到.dll库中的对象类型依赖于编译时发生的事情可能会遇到问题,直到我看到问题Could I ignore C4251 warning in this case?事实上,如果库的编译设置和使用库的程序是不同的,可能会发生一些错误。这里有一个例子:为什么我会有运行时检查失败错误?

dll.h

#include <iostream> 
    #include <string> 

    using namespace std; 

    class __declspec(dllexport) HelloWorld 
    { 
    public: 
    #ifdef DTEST 
     int test; 
    #endif 
     HelloWorld(); 

    }; 

dll.cpp

#include "dll.h" 

HelloWorld::HelloWorld() 
{ 
#ifdef DTEST 
    test=0; 
#endif 
} 

exe.cpp

#include "dll.h" 
#include <iostream> 
using namespace std; 

int main(void) 
{ 
    HelloWorld myworld; 

    return 0; 
} 

如果我编译dll.h和dll.cpp到用DTEST的定义创建dll.lib和dll.dll,但不用DTEST的定义编译exe.cpp。我将有一个运行时检查失败#2错误。有人可以解释为什么我有这个错误。谢谢!

+2

您是否期望您的程序运行?你会如何证明它? – 2013-05-03 16:49:00

你有这个错误,因为DTEST是一个预处理器的宏,你没有为你的程序的所有部分一致地定义它。当代码到达实际编译器时,它会被完全删除,所以编译器不会发现问题。如果你定义DTESTdll.cpp而不是exe.cpp,然后exe.cpp看起来像这样的编译器:

(...contents of <iostream>...) 
(...contents of <string>...) 

using namespace std; 

class __declspec(dllexport) HelloWorld 
{ 
public: 
    HelloWorld(); 

}; 

(...contents of <iostream> again...) 
using namespace std; 

int main(void) 
{ 
    HelloWorld myworld; 

    return 0; 
} 

然而,dll.cpp看起来就像这样:

(...contents of <iostream>...) 
(...contents of <string>...) 

using namespace std; 

class __declspec(dllexport) HelloWorld 
{ 
public: 
    int test; 
    HelloWorld(); 

}; 

HelloWorld::HelloWorld() 
{ 
    test=0; 
} 

这里的问题是dll.cppexe.cppHelloWorld有两个不同的想法:dll.cpp认为它包含test,但exe.cpp认为它不是。有一个运行时检查,捕捉这种不匹配,这是你所看到的。

编译器看到的是预处理器扩展的结果。 在您的例子,编译器看到:

class HelloWorld 
{ 
public: 
    int test; 
    HelloWorld(); 
}; 
dll.cpp

,并

class HelloWorld 
{ 
public: 
    HelloWorld(); 
}; 
exe.cpp

。同一类,两个不同的定义。这是 违反了一个定义规则,导致 未定义的行为。

这与C4251警告无关(如果我正确理解 ,只关心不同的 DLL之间的链接)。