【发布时间】:2012-09-15 10:37:50
【问题描述】:
我无法在可以展示的较小程序中复制此问题,因此我将通过屏幕截图说明问题。
我有一个声明联合的类和联合的静态成员:
class
{
/* rest of the class */
union EmptyString
{
char8 m_Empty8[1];
uchar8 m_EmptyU8[1];
char32 m_Empty32[1];
};
static const EmptyString sm_emptyString;
};
// Definition
template <typename T>
const typename StringBase<T>::EmptyString
StringBase<T>::sm_emptyString = { 0 };
然后我有一个返回字符串地址的函数。出于调试目的,我添加了变量address,以便可以将其添加到监视窗口。这是函数(T 这里是 char8 其中char8 是 char 的 typedef):
template <typename T>
const char8* StringBase<T>::GetEmptyString( char8 )
{
const char8* address = sm_emptyString.m_Empty8;
//const char8* address = &(sm_emptyString.m_Empty8[0]);
return address;
//return sm_emptyString.m_Empty8;
}
如您所见,最初我有一个 return 语句,我将其注释掉以便调试 sn-p。被注释掉的另一行是获取数组的第一个(也是唯一一个)元素的地址;这条被注释掉的行与它之前的行做同样的事情,即:const char8* address = sm_emptyString.m_Empty8;。
程序崩溃是因为我没有通过上述函数获得正确的地址,这让我很困惑。下面我将开始我的调试会话的截图:
在上面,你可以看到我在地址被复制到指针之前就中断了。以下是sm_emptyString 和address 在此休息时间的观察窗口值。
到目前为止,没有什么特别的。下面是单步执行一行代码后的截图。
以及对应的观察窗口:
如您所见,复制到address 的值是错误的。另外需要注意的是,这个函数被调用了几次,静态变量地址到address 的副本是正确的。当地址不正确并由函数返回时,我的程序会崩溃(因为稍后在程序中对地址进行了假设)。
这里发生了什么?我是否在某处覆盖了内存?我该如何调试呢?
编辑:
反汇编(根据调试器,sm_emptyString的地址是129F184,与反汇编显示的128F134不同):
template <typename T>
const char8* StringBase<T>::GetEmptyString( char8 )
{
0119B850 push ebp
0119B851 mov ebp,esp
0119B853 push ecx
0119B854 mov dword ptr [ebp-4],0CCCCCCCCh
const char8* address = sm_emptyString.m_Empty8;
0119B85B mov dword ptr [address],offset StringBase<char>::sm_emptyString (128F134h)
//const char8* address = &(sm_emptyString.m_Empty8[0]);
return address;
0119B862 mov eax,dword ptr [address]
//return sm_emptyString.m_Empty8;
}
我正在使用什么: Windows 7,VC++ 2008,调试版本
【问题讨论】:
-
如果您将联合成员从 1 元素数组更改为只是一个简单的变量会发生什么?即
union { char8 m_Empty8; ... },然后将地址分配为const char8* address = &(sm_emptyString.m_Empty8);。你还遇到同样的问题吗? -
如果你把 union 改成 struct 会发生什么? (只需用结构替换 union 关键字)。你还遇到同样的问题吗?
-
除此之外,尝试将
char8 m_Empty8[1]和朋友更改为直接指针。所以改为char8 *m_Empty8。 -
您实际上是定义您的
static成员还是您只声明了它?鉴于您既没有显示定义也没有给包含union的类命名,这可能是问题所在。 -
@DietmarKühl 如果他没有定义它就不会编译是吗?