bool g_Flag = false;
bool getbFlag()
{
return g_Flag;
}
void setFlag(bool b)
{
g_Flag = b;
}
A.h中的内容是:
bool getFlag();
void steFlag(bool b);
本人在B.cpp中包含了A.h
然后在某个函数中setFlag(true);,随后本人就调用getFlag()发现是返回true的;可是本人在C.cpp中在调用时发现getFlag()返回了false,可以肯定的是其他再没有修改这个变量的地方,而且C的调用在B的调用之后,这样诡异的问题,可能的原因是什么呢?本人也完全编译了一次程序,折腾大半天就是不行。还有假如本人初始化为true,那么C中调用时就返回true了。
5
1)全局变量,应该定义为易变的,防止编译优化错误。
2)读写全局变量,应该同步
5
extern bool g_Flag; bool getFlag(); void steFlag(bool b);
5
5
5
5
5
这是你从代码看的吧。能不能加上打印输出,证明确实是先调了B才调C
5
加锁,使用信号量…
10
溢出覆盖等等,真想只有一个
5
#include <time.h> #include <stdlib.h> #include <windows.h> int main() { int a,b[11];//本来是b[10],为判断哪句越界,故意声明为b[11] srand((unsigned int)time(NULL));//按两次F11,等黄色右箭头指向本行时,调试、新建断点、新建数据断点,地址:&b[10],字节计数:4,确定。 while (1) {//按F5,会停在下面某句,此时a的值为10,b[10]已经被修改为对应0..4之一。 b[(a=rand()%11)]=0; Sleep(100); b[(a=rand()%11)]=1; Sleep(100); b[(a=rand()%11)]=2; Sleep(100); b[(a=rand()%11)]=3; Sleep(100); b[(a=rand()%11)]=4; Sleep(100); } return 0; }
10
例如有一个A.cpp和A.h;cpp中顶一个一个全局bool和获取设置的函数
bool g_Flag = false;
bool getbFlag()
{
return g_Flag;
}
void setFlag(bool b)
{
g_Flag = b;
}
A.h中的内容是:
bool getFlag();
void steFlag(bool b);
本人在B.cpp中包含了A.h
然后在某个函数中setFlag(true);,随后本人就调用getFlag()发现是返回true的;可是本人在C.cpp中在调用时发现getFlag()返回了false,可以肯定的是其他再没有修改这个变量的地方,而且C的调用在B的调用之后,这样诡异的问题,可能的原因是什么呢?本人也完全编译了一次程序,折腾大半天就是不行。还有假如本人初始化为true,那么C中调用时就返回true了。
不用加volatile,要加上extern。
不加extern的话,表面上不同的cpp #include 同一个”A.h”,实际上bool g_Flag并非全局,只是局部于本cpp单元的变量。
不信 不同的cpp可以输出各自的&g_Flag 确认。
5
10
不用加volatile,要加上extern。
不加extern的话,表面上不同的cpp #include 同一个”A.h”,实际上bool g_Flag并非全局,只是局部于本cpp单元的变量。
不信 不同的cpp可以输出各自的&g_Flag 确认。是给函数加还是变量加,本人都加了也没有作用,包括直接使用变量,不调用get函数一样是false
A.h增加一个函数 bool* getFlagAddr()
或调试getFlag断点看g_Flag的内存地址。
5
不然就加锁
Windows 临界区,互斥量,都可以。
2
5
不用加volatile,要加上extern。
不加extern的话,表面上不同的cpp #include 同一个”A.h”,实际上bool g_Flag并非全局,只是局部于本cpp单元的变量。
不信 不同的cpp可以输出各自的&g_Flag 确认。是给函数加还是变量加,本人都加了也没有作用,包括直接使用变量,不调用get函数一样是false
A.h增加一个函数 bool* getFlagAddr()
或调试getFlag断点看g_Flag的内存地址。调试时通过查看这个变量的地址发现,B中通过setFlag改变的好像不是那个全局的bool,C后来调用的才是那个全局bool,总之就是两个地址,但同一个变量为什么会有两个地址?
本人感觉 并没有全局的bool,都是局部的bool。你可以增加一个D单元来验证一下。
5
5
或
将你的全局变量放在一个明确的自定义命名空间里,且引用:
加static有用么?
看题主已经实现了set和get接口,那么何不用static限制你的全局变量的作用文件,只在本文件生效,这样也不用怕别人外部extern后改掉它
不存在在其他地方被改变的可能,原因是这个被引用:
加static有用么?
显然没用,本人要在不同的文件中用这个变量的
贴几个单元的代码吧
代码没什么好贴得,就是主贴中说的那些东西了,现在问题就是不同的文件里这个变量的地址不同,也就是本人修改的时候(B文件)的地址和后来C中调用时的地址不相同,也就是修改的不是一个东西,但是本人确信这个变量就只有这一个,不存在什么局部有定义等等的说法
你不是有接口么,都用函数接口访问啊
2
加static有用么?
显然没用,本人要在不同的文件中用这个变量的
贴几个单元的代码吧
代码没什么好贴得,就是主贴中说的那些东西了,现在问题就是不同的文件里这个变量的地址不同,也就是本人修改的时候(B文件)的地址和后来C中调用时的地址不相同,也就是修改的不是一个东西,但是本人确信这个变量就只有这一个,不存在什么局部有定义等等的说法
你不是有接口么,都用函数接口访问啊
就是用函数访问这个变量的。现在的问题是调试时这个变量的地址有多个,在B文件中修改的是地址为X的,在C文件里访问到的是地址为Y的
你试过本人46L说的方法吗?出现一个变量多个地址,明显就是在多个编译单元中出现了同名的变量啊,这一般不就是木有加extern造成的嘛。假如源文件既有c,又有cpp,估计还要加extern “C”
3
刚才调试,遇到其他空指针抛异常程序中途退出了,release运行没有这种异常,本人点击“忽略”也不行,本人想先不管这个先把这个全局变量问题搞明白了,不知道怎么忽略这个问题?
也许应该先把空指针问题解决了,这个诡异的问题就消失了。这个诡异的问题也许就是空指针问题导致的。
2
2
5
那两个函数 应该导出的.
2
10
那就是模块的问题了,你的cpp是不是也被几个模块包含了.
那两个函数 应该导出的.昨晚突然意识到这个B.cpp是在一个dll中的源文件,而A.cpp是主程序和动态库都用的一个源文件,这样的话就形成了两种地址,一种是动态库中该变量的地址,一种是主程序中该变量的地址,在B中修改的应该是动态库中的内存空间的地址,而C中调用的是主程序中的,所以有两种地址,这个是本人的猜测,估计就是这一个原因了,那本人动态库里怎么样访问到主程序那个变量呢?假如按照现在的extern的话也是两份变量,怎么样真正共用一个变量呢?
A.cpp同时存在于主程序和动态库?那相当于有两个你定义的全局变量了,所以会有两个地址存在,读写都是不同的,
2
5
那就是模块的问题了,你的cpp是不是也被几个模块包含了.
那两个函数 应该导出的.昨晚突然意识到这个B.cpp是在一个dll中的源文件,而A.cpp是主程序和动态库都用的一个源文件,这样的话就形成了两种地址,一种是动态库中该变量的地址,一种是主程序中该变量的地址,在B中修改的应该是动态库中的内存空间的地址,而C中调用的是主程序中的,所以有两种地址,这个是本人的猜测,估计就是这一个原因了,那本人动态库里怎么样访问到主程序那个变量呢?假如按照现在的extern的话也是两份变量,怎么样真正共用一个变量呢?
A.cpp同时存在于主程序和动态库?那相当于有两个你定义的全局变量了,所以会有两个地址存在,读写都是不同的,
确实是这个原因,本人现在通过动态库中的接口的返回值来判断能否在dll中修改了这个bool,也就是说dll中改不改这个已经无所谓了,改了也只是dll内部的那个,本人主程序只要后来知道dll中改没改就可以了。假如本人现在想在动态库中修改到主程序的那一份,怎么样做比较方便呢?或说主程序中的怎么样真正和dll共享一份呢?
搞清楚了原因就行了;这样可将全局变量声明到A.h中,用到这个全局全变量的文件不包含A.h,只加外部声明:extern bool b_Flag;这样就行了,在其他编译单元中该读就读,该写就写;直接用这个变量就行了;
2
另外说dll与exe程序处于不同地址空间的,纯属本人臆想。
5
#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;
}
15
10
建议把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;
}假如本人主程序中也要用这个全局变量呢?只有从dll中的接口来取或改?除了这样还有没有更加简便的实现共享数据的方法?
这也是一种方法,下面说说本人的方法:
1、建一个dll工程,仅包含两个文件:dll.h和dll.cpp
如下结构:
dll.h:
#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); }
dll.cpp
#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; } };
2、新建一个console application Demo;Demo和dll放在同一个sln下面,Demo包含三个文件:A.h、A.cpp、main.cpp
A.h如下:
#include "../dll/dll.h"//包含dll.h中对g_Flag的声明 extern "C" { __declspec(dllexport) bool getAFlag(); __declspec(dllexport) void setAFlag(bool flag); };
A.cpp如下:
#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; } };
main.cpp如下:
// 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; }
运行结果如下:
5
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中,则不能直接达到目的,还是有办法达到目的的,但在这里不讨论
以下理解难免有错误之处,望大神不吝指点!
5
dll中不要保存状态(static, 全局变量等),原因是dll可以被动态加载/卸载, 导致设计更复杂,更容易出问题.
屎山依然形成,本人已无力回天,只做最少的改动。呵呵
HMODULE h=LoadLibrary(“dll.dll”);//动态加载
if(h!=0)
{
FARPROC a=GetProcAddress(h,”g_Flag”);//找到g_Flag的地址,
if(a!=0)
{
cout<<hex<<a<<“=”<<dec<<*(bool*)(a)<<endl;//输出,或修改
}
}
不过正如大神所讲,dll中少保存状态,除非你确保不会在使用中动态卸载