65,179
社区成员




屎山依然形成,我已无力回天,只做最少的改动。呵呵 dll中不要保存状态(static, 全局变量等),因为dll可以被动态加载/卸载, 导致设计更复杂,更容易出问题.
dll中不要保存状态(static, 全局变量等),因为dll可以被动态加载/卸载, 导致设计更复杂,更容易出问题.
1、在主程序中不能定义,否则就出现了两个同名的变量 2、读取与修改变量均通过dll提供的导出接口来完成; 3、你完全可以不在主程序中直接使用变量值,而是调用dll导出的getFlag()和setFlag()来完成使用的目的,这样就不需要在dll中导出g_Flag了; 4、使用全局变量有危险的,会导致出错难以查找,尤其是在多线程编程是更是存在此问题,所以如果在多个地方需要即读又写,建议还是给dll导出的getFlag()、setFlag()加入互斥锁,同时不在dll中导出g_Flag,以免有的越过锁直接修改变量;通过调用加锁的getFlag()和setFlag()能保证所有的值都是正确的,而不会出现一处修改,另一处未同步的情况,所以不建议在主程序中直接使用g_Flag变量,不论读与写,都不建议
[quote=引用 76 楼 lianshaohua 的回复:] 原因解析: 1、全局变量放在dll中,并在dll的头文件中只声明不定义,但需要根据定义的宏指定是导出还是导入,因为dll.h需要我主程序中使用,在主程序中使用时为dllimport导入符号;在dll工程中使用时为导出符号(详见dll.h);为了简单,没有将函数的导出像g_Flag那样一样写,最好是定义导出、导入宏来实现 2、在demo工程中,需要指定dll.lib链接库,其中存放了dll工程导出的符号:g_Flag、setFlag()、getFlag()等,其实就是一个符号表,指示链接程序如何找到符号;在使用过程中常常导出函数,变量一样可以导出,因为都是地址(太浅显的理解了,大牛们勿喷,给新手我一些面子) 3、在demo中包含dll.h对所有导出符号的声明,这样在main.cpp中就能直接使用g_Flag的声明了,因为demo中不包含对DLL_EXPORTS宏的定义,所以就是导入g_Flag了,其他的符号也是如此 4、在编译时,先编译dll工程,将符号导出;再编译demo工程,这样link.exe才能在dll.lib中找到 需要的符 号,如此,demo和dll中使用的是同一个变量——dll中的变量; 5、如果变量放在demo中,则不能直接达到目的,还是有办法达到目的的,但在这里不讨论 以下理解难免有错误之处,望大牛不吝指教!
也可以把exe中的g_flag的地址(指针)传到dll中,dll保存一份地址(指针),由于备份地址可能被其他的exe修改,所以这个dll只能被这一个exe使用了,不能再被其他exe映射了。与使用dll的初衷冲突,不建议。
原因解析: 1、全局变量放在dll中,并在dll的头文件中只声明不定义,但需要根据定义的宏指定是导出还是导入,因为dll.h需要我主程序中使用,在主程序中使用时为dllimport导入符号;在dll工程中使用时为导出符号(详见dll.h);为了简单,没有将函数的导出像g_Flag那样一样写,最好是定义导出、导入宏来实现 2、在demo工程中,需要指定dll.lib链接库,其中存放了dll工程导出的符号:g_Flag、setFlag()、getFlag()等,其实就是一个符号表,指示链接程序如何找到符号;在使用过程中常常导出函数,变量一样可以导出,因为都是地址(太浅显的理解了,大牛们勿喷,给新手我一些面子) 3、在demo中包含dll.h对所有导出符号的声明,这样在main.cpp中就能直接使用g_Flag的声明了,因为demo中不包含对DLL_EXPORTS宏的定义,所以就是导入g_Flag了,其他的符号也是如此 4、在编译时,先编译dll工程,将符号导出;再编译demo工程,这样link.exe才能在dll.lib中找到 需要的符 号,如此,demo和dll中使用的是同一个变量——dll中的变量; 5、如果变量放在demo中,则不能直接达到目的,还是有办法达到目的的,但在这里不讨论 以下理解难免有错误之处,望大牛不吝指教!
[quote=引用 71 楼 nil_affliction 的回复:]
建议把g_flag在dll中定义为进程间数据共享,然后export function提供给exe使用。
#pragma data_seg ("shareddata")
bool g_flag = true;//共享数据
#pragma data_seg()
__declspec(dllexport) void set_flag(bool flag)
{
g_flag = flag;
}
__declspec(dllexport) bool get_flag()
{
return g_flag;
}
#pragma once
extern "C"
{
#ifdef DLL_EXPORTS
__declspec(dllexport) extern bool g_Flag;//只导出声明,导出定义
#else
__declspec(dllimport) extern bool g_Flag;
#endif
__declspec(dllexport) bool getFlag();
__declspec(dllexport) void setFlag(bool flag);
}
#include "stdafx.h"
#include "dll.h"
#include <iostream>
using namespace std;
extern "C"
{
__declspec(dllexport) bool g_Flag=true;//真正的定义在这里
__declspec(dllexport) bool getFlag()
{
cout<<"dll,"<<hex<<&g_Flag<<"="<<dec<<g_Flag<<endl;//输出值的同时输出变量地址
return g_Flag;
}
__declspec(dllexport) void setFlag(bool flag)
{
g_Flag=flag;
}
};
#include "../dll/dll.h"//包含dll.h中对g_Flag的声明
extern "C"
{
__declspec(dllexport) bool getAFlag();
__declspec(dllexport) void setAFlag(bool flag);
};
#include "stdafx.h"
#include "A.h"
#include <iostream>
using namespace std;
extern "C"
{
__declspec(dllexport) bool getAFlag()
{
cout<<"a.cpp,"<<hex<<&g_Flag<<"="<<dec<<g_Flag<<endl;//输出的同时输出地址
return g_Flag;
}
__declspec(dllexport) void setAFlag(bool flag)
{
g_Flag=flag;
}
};
// ConsoleApplication3.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
using namespace std;
#pragma comment(lib,"../Debug/dll.lib")//链接库,包含了调用dll.h是声明的一切符号,如:g_Flag、getFlag(),setFlag()等符号
#include "../dll/dll.h"//导入dll.h可以完全使用g_Flag
#include "A.h"//导入A.h只为测试A.h中声明的两个函数,其实完全可以不使用A.h中的函数;只使用dll.h中的函数来完成显示与设置g_Flag的功能
int _tmain(int argc, _TCHAR* argv[])
{
cout<<"main,"<<hex<<&g_Flag<<"="<<dec<<g_Flag<<endl;
getFlag();
getAFlag();
g_Flag=false;//通过g_Flag直接修入值
cout<<"main,"<<hex<<&g_Flag<<"="<<dec<<g_Flag<<endl;
getFlag();
getAFlag();
getchar();
setAFlag(true);/通过setAFlag()修改g_Flag值
cout<<"main,"<<hex<<&g_Flag<<"="<<dec<<g_Flag<<endl;
getFlag();
getAFlag();
getchar();
return 0;
}
建议把g_flag在dll中定义为进程间数据共享,然后export function提供给exe使用。 #pragma data_seg ("shareddata") bool g_flag = true;//共享数据 #pragma data_seg() __declspec(dllexport) void set_flag(bool flag) { g_flag = flag; } __declspec(dllexport) bool get_flag() { return g_flag; }
我如果把A.cpp从动态库项目中删除的话,会报无法解析的外部符号xxx.也就是dll中用到的几个函数就找不到函数体了,即使我假如那个A.h,并且在它里边extern 那些函数声明也是不行的,也就是缺实现,可我的这个全局变量又定义在了这个A.cpp中,也找不到其他合适的地方放,不知道如何搞了 在主程序中包含a.cpp,在dll工程中也包含了a.cpp肯定是两份的,因为a.cpp中有b_Flag的声明和定义
在主程序中包含a.cpp,在dll工程中也包含了a.cpp肯定是两份的,因为a.cpp中有b_Flag的声明和定义