首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

全局变量被修改后又还原为初始值的诡异有关问题

2014-01-05 
全局变量被修改后又还原为初始值的诡异问题比如有一个A.cpp和A.hcpp中顶一个一个全局bool和获取设置的函

全局变量被修改后又还原为初始值的诡异问题
比如有一个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了。
[解决办法]
而且C的调用在B的调用之后
这是你从代码看的吧。能不能加上打印输出,证明确实是先调了B才调C
[解决办法]


[解决办法]
引用:
Quote: 引用:


不用加volatile,要加上extern。
不加extern的话,表面上不同的cpp #include 同一个"A.h",实际上bool g_Flag并非全局,只是局部于本cpp单元的变量。

不信 不同的cpp可以输出各自的&g_Flag 确认。
是给函数加还是变量加,我都加了也没有作用,包括直接使用变量,不调用get函数一样是false


A.h增加一个函数 bool* getFlagAddr()
或者调试getFlag断点看g_Flag的内存地址。
[解决办法]
Interlock系列函数 可以对32Bits数据同步
不然就加锁
Windows 临界区,互斥量,都可以。

[解决办法]
明显是定义了两个变量
[解决办法]
引用:

Quote: 引用:

Quote: 引用:

Quote: 引用:


不用加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单元来验证一下。
[解决办法]
定义在头文件中了吧,写cpp里。
[解决办法]
重建所有
或者
将你的全局变量放在一个明确的自定义命名空间里,且引用时指明命名空间象ios_base::hex这样
再试试?

[解决办法]
感觉你这c.cpp里有一个同名的变量呢
[解决办法]
貌似全局变量是要定义在 h文件的。
[解决办法]
贴几个单元的代码吧
[解决办法]
加static有用么?
[解决办法]
引用:
Quote: 引用:

Quote: 引用:

加static有用么?


看楼主已经实现了set和get接口,那么何不用static限制你的全局变量的作用文件,只在本文件生效,这样也不用怕别人外部extern后改掉它
不存在在其他地方被改变的可能,因为这个被引用的地方就只有很少的2,3处,而且都是改为true,根本没有改为false的代码,现在就是同一个变量在不同的文件里的地址不相同


的确很诡异,SetFlag的所有引用也查找了吗,,,会不会有多余的SetFlag(false)的操作噢。。
[解决办法]
c中调用的getFlag()确定是A中的getFlag()?
[解决办法]
引用:
Quote: 引用:

加static有用么?
显然没用,我要在不同的文件中用这个变量的

引用:
贴几个单元的代码吧
代码没什么好贴得,就是主贴中说的那些东西了,现在问题就是不同的文件里这个变量的地址不同,也就是我修改的时候(B文件)的地址和后来C中调用时的地址不相同,也就是修改的不是一个东西,但是我确信这个变量就只有这一个,不存在什么局部有定义等等的说法

你不是有接口么,都用函数接口访问啊
[解决办法]
引用:
Quote: 引用:

Quote: 引用:

Quote: 引用:

加static有用么?
显然没用,我要在不同的文件中用这个变量的

引用:
贴几个单元的代码吧
代码没什么好贴得,就是主贴中说的那些东西了,现在问题就是不同的文件里这个变量的地址不同,也就是我修改的时候(B文件)的地址和后来C中调用时的地址不相同,也就是修改的不是一个东西,但是我确信这个变量就只有这一个,不存在什么局部有定义等等的说法

你不是有接口么,都用函数接口访问啊
就是用函数访问这个变量的。现在的问题是调试时这个变量的地址有多个,在B文件中修改的是地址为X的,在C文件里访问到的是地址为Y的


你试过我46L说的方法吗?出现一个变量多个地址,明显就是在多个编译单元中出现了同名的变量啊,这一般不就是木有加extern造成的嘛。如果源文件既有c,又有cpp,估计还要加extern "C"
[解决办法]
引用:
刚才调试,遇到其他空指针抛异常程序中途退出了,release运行没有这种异常,我点击“忽略”也不行,我想先不管这个先把这个全局变量问题搞明白了,不知道怎么忽略这个问题?


也许应该先把空指针问题解决了,这个诡异的问题就消失了。这个诡异的问题也许就是空指针问题导致的。
[解决办法]
先搞清楚真正的全局变量再说啊!真正的全局怎么可能没有extern呢?
[解决办法]
打数据断点看哪儿修改了
[解决办法]
那就是模块的问题了,你的cpp是不是也被几个模块包含了.

那两个函数 应该导出的.
[解决办法]
确定不是多线程情况下的缓存?
[解决办法]
引用:
Quote: 引用:

那就是模块的问题了,你的cpp是不是也被几个模块包含了.

那两个函数 应该导出的.
昨晚突然意识到这个B.cpp是在一个dll中的源文件,而A.cpp是主程序和动态库都用的一个源文件,这样的话就形成了两种地址,一种是动态库中该变量的地址,一种是主程序中该变量的地址,在B中修改的应该是动态库中的内存空间的地址,而C中调用的是主程序中的,所以有两种地址,这个是我的猜测,估计就是这一个原因了,那我动态库里如何访问到主程序那个变量呢?如果按照现在的extern的话也是两份变量,如何真正共用一个变量呢?


A.cpp同时存在于主程序和动态库?那相当于有两个你定义的全局变量了,所以会有两个地址存在,读写都是不同的,
[解决办法]
动态库包含进去,也是在主程序的进程空间里面的的一部分,不是独立的空间
[解决办法]
引用:
Quote: 引用:

Quote: 引用:

Quote: 引用:

那就是模块的问题了,你的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;这样就行了,在其他编译单元中该读就读,该写就写;直接用这个变量就行了;
[解决办法]
个人比较认可46楼的代码。
另外说dll与exe程序处于不同地址空间的,纯属自己臆想。
[解决办法]
建议把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;
}
[解决办法]
也可以把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: 引用:

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中少保存状态,除非你确保不会在使用中动态卸载

热点排行