用vs编译动态库需要注意的问题,全局变量初始化

时间:2021-01-04 19:42:00

用vs编译动态库如果配置错误会导致全局变量不能初始化。

例子:

string a="hello";
char b="hello";
int main(int arg,char* argv[])
{
printf("string a=%s",a.c_str());
printf("char* b=%s",b);
}

编译成exe后,你可能会认为都是输出“hello”,但实际结果不尽如此。这取决于你的工程设置。

如果工程属性里,链接器,入口函数设置为main,那么结果只有b被打印了,a为空:即:string a=char* b=hello;

这是为什么呢?

Window和wince的动态库存在一个入口函数,是_DllMainCRTStartup ,这里面会调用_CRT_INIT,这里面会初始化运行时库的全局变量和静态全局变量。

其实这一点对于exe应用也是一样的,但逻辑不同,exe的入口默认是mainCRTStartup,里面同样会初始化全局变量和静态非全局变量。

也就是说如果你设置了入口函数,系统不会调用_CRT_INIT 来执行调用构造函数,但是char* 是c语言

下面是MSDN的解释:

C/C++ 运行时库代码执行 DLL 启动序列,从而不必像 Windows 3.x 中那样必须链接到单独的模块。C/C++ 运行时库代码中包含的是名为 _DllMainCRTStartup 的 DLL 入口点函数。_DllMainCRTStartup 函数执行若干操作,其中包括调用 _CRT_INIT,此操作初始化 C/C++ 运行时库并在静态非局部变量上调用 C++ 构造函数。如果没有此函数,运行时库将保持未初始化状态。_CRT_INIT 既可以用于静态链接的 CRT,也可以从用户 DLL 链接到 CRT DLL Msvcrt.dll。

虽然可以使用 /ENTRY: 链接器选项指定其他入口点函数,但不建议这样做,因为新的入口点函数将不得不重复_DllMainCRTStartup 执行的所有操作。用 Visual C++ 生成 DLL 时,系统自动链接 _DllMainCRTStartup,您无需使用 /ENTRY: 链接器选项指定入口点函数。

除了初始化 C 运行时库外,_DllMainCRTStartup 还调用名为 DllMain 的函数。根据生成的 DLL 类型的不同,Visual C++ 为您提供 DllMain 并使它被链接,以便 _DllMainCRTStartup 始终有东西可以调用。这样,如果不需要初始化 DLL,则在生成 DLL 时没有什么特别的事情要做。如果需要初始化 DLL,添加代码的位置取决于编写的 DLL 类型。有关更多信息,请参见初始化 DLL

C/C++ 运行时库代码在静态非局部变量上调用构造函数和析构函数。例如,在以下 DLL 源代码中,Equus 和 Sugar 是 CHorse 类的两个静态非本地对象,它们都是在 Horses.h 中定义的。由于这些对象是在所有函数的外部定义的,源代码中没有任何函数包含对CHorse 的构造函数或对析构函数的调用。因此,必须由运行时代码执行对这些构造函数和析构函数的调用。应用程序的运行时库代码也执行此函数。