我的 VC++ 调试技巧

1.没有解决的外部定义错误
xyView.obj : error LNK2001: unresolved external symbol "public: __thiscall CMyOCRInfo::CMyOCRInfo(void)" (??0CMyOCRInfo@@QAE@XZ)
可能是由于构造方法没有实现代码

2.没有释放 HBITMAP 句柄造成不能创建位图的问题
2004.8.17
没有及时的释放 HBITMAP 句柄,当创建位图数达到 30 时,出现 8 号错误,即内存不足

3.在调试窗口输出信息
TRACE(s);

4.如果用向导新建类时只有自定义类型,则可能是因为 .clw 文件没有生成,生成该文件即可

5.要注意变量的类型范围,强制转换可能会导致数据溢出;下面的示例将导致死循环:
for(byte i=0;i<256;i++){
    ... ...
}
注:由于 byte 类型的表示范围为:0-255 ,因此 i 永远不可能大于 255 ,所以导致死锁

6.没有包含 stdafx.h 导致的错误:
fatal error C1010: unexpected end of file while looking for precompiled header directive
在 .cpp 文件中包含 stdafx.h 文件即可

7.避免重复包含头文件
#ifndef _INC_PUBLIC_H_32564987132178947
#define _INC_PUBLIC_H_32564987132178947

// 中间写代码
...

#endif

注:#ifndef 可以改为 #if !defined

8.出现重复定义错误,例如:
d:/program files/microsoft visual studio/vc98/include/dbdaoint.h(33) : error C2011: 'EditModeEnum' : 'enum' type redefinition
先检查所有的 .h 文件中是否定义了 include "stdafx.h" ,删之
再在所有的 .cpp 文件中搜索 stdafx ,看是否重复包含了 stdafx.h 文件,把重复的删掉

又如:
RefImageDll.obj : error LNK2005: "int __cdecl GetCameraRefImageIndexOfID1(class CArray<class CCameraRefImage,class CCameraRefImage> &,int)" (?GetCameraRefImageIndexOfID1@@YAHAAV?$CArray@VCCameraRefImage@@V1@@@H@Z) already defined in InterFaceFile.obj
是因为在 .h 文件中定义了一个函数,且做了完整的实现,因此被多个文件包含时就会出现重复定义错误,解决的方法是
把该函数定义成 inline ,这样就不再是一个函数而直接采用一段代码替换了,如:
int inline GetAge(){
    return 10;
}

9.类定义不完整,例如:
refimagedll.h(14) : error C2236: unexpected 'class' 'CRefImageListDll'
一般是因为在该文件包含的文件中存在类定义不完整,例如:
calss a{
    int age;
}
后面少了一个分号,应该改成:
class a{
    int age;
};

10.纯虚类不能生成实例,例如:
d:/program files/microsoft visual studio/vc98/mfc/include/afxtempl.h(201) : error C2259: 'CKernel' : cannot instantiate abstract class due to following members:
如下:
class a{
public:
    virtual void SetValue(int i)=NULL;
}

class b : public a{
private:
    int    m_iID;
public:
}
这样的话,B 也不能实例化,因为在 B 中没有实现 SetValue() 方法,在 B 中实现 SetValue() 方法即可解决。

11.重复释放导致的问题
User breakpoint called from code at 0x77f9193c
以上原因是由于释放了一个类的成员,最后在作该类的析构时由于它的成员已经被释放导致出错(该成员被释放但是没有设 NULL)

12.试图执行系统不支持的操作
请检查当前窗口模块是否使用了其他不属于它自己的资源

13.在 Dll 里调用对话框等资源的方法(如何在动态链接库中显示对话框) 2006.7.24
在动态链接库的显示对话框函数中加入下面这句代码即可:
AFX_MANAGE_STATE(AfxGetStaticModuleState());
如果需要导出对话框的对象,在外面进行显示,则可以重载 DoModal() 方法,在该方法中加入 AFX_MANAGE_STATE(AfxGetStaticModuleState());

14.动态链接库和静态链接库混用的问题
症状:使用 LoadLibrary() 加载一个动态链接库时,返回 0 ,函数不成功,调用 GetLastError() 返回结果 126 ,MSDN 如是说:
126 The specified module could not be found.  ERROR_MOD_NOT_FOUND
经研究发现,是因为该动态链接库采用了静态的方式调用了另一个链接库(B),而另一个链接库则又采用静态的方式调用了另一个动态链接库(C),但是 C 却没有拷贝到程序所在目录,所以导致不能正常加载

15.宏定义导致系统出错
连出三个错误:
ignored on left of 'unsigned char' when no variable is declared
error C2143: syntax error : missing ';' before 'constant'
error C2106: '=' : left operand must be l-value
代码如下:
    byte R=(byte)(AColor & 0xFF);
如果按照常理,应该不会有问题,但是由于一个函数库里面对 R 有定义,所以 R 便不能当做变量使用

16.Debug 版本的 GetDocument() 函数可用,而 Release 版本则不能使用,提示函数没有实现代码
检查 .h 文件中最后是否函数如下代码:
#ifndef _DEBUG  // debug version in LCDModelView.cpp
inline CXXXDoc* CXXXView::GetDocument()
{ return (CXXXDoc*)m_pDocument; }
#endif
原理:对于从来都没有调用的函数,可以没有其实现代码,如果含有有一处调用则一定要有其实现代码,微软采用宏定义来区分 Release 和 Debug 版本。

17.VC 环境下不能使用 FindFile 进行文件搜索的问题(刘栋嫣发现,陆宽解决 2007.3.1)
在 VC 的集成开发环境下,点击搜索文件按钮,VC 崩溃
检查注册表键:HKEY_CURRENT_USER/Software/Microsoft/DevStudio/6.0/SearchOld/FIF_InFolders
发现其值为一个不存在的目录,导致崩溃,解决办法是清除该键值即可


18.函数的参数要记得使用(2007.3.28)
如:error C2220: warning treated as error - no object file generated
或:warning C4100: 'AParamCount' : unreferenced formal parameter

19.VC工程每次都重新编译(2007.4.18 王郑发现)
问题:VC工程每次点击 F7,F5或Ctrl+F5时,都会全部编译
解决:发现是系统的时间比工程的创建时间早,导致该问题发生

20.DLL 的导出方式(2007.6.1)
  1.在 def 文件中导出,格式为:Function @n 例如:ShowName @1
  2.直接在函数的声明加上 _declspec(dllexport) 标识符
  需要注意的是:第一种只能导出函数,不能导出类,而第二种即可导出函数也可导出类
  第二种方法有个问题:只能提供给 VC 的程序进行静态的调用,因为其导出的函数名加上了参数的信息,例如:“?ShowName@@YAXXZ
  解决的办法是在其声明的前面加上 extern "C" ,例如:extern "C" _declspec(dllexport) void ShowName()
  综上所述:第二种方法既能支持静态调用又能支持动态调用,并且还能支持类的导出
示例见附件

21.修改系统默认的调试器(2007.6.29)
Win2000:  
  注册表:HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/WinNT/CurrentVersion/AeDebug  
  "C:/Program   Files/Visual   Studio/Common/MSDev/Bin/msdev.exe"   -p   %ld   -e   %ld  

22.动态库中 CString 函数析构时出错(2008.2.25)
问题描述:用 CString 作为参数传递,主程序采用 Debug 版本编译,DLL 采用 Release 编译
在 CString 析构时出错
解决方法是把主程序和DLL都采用 Debug 或 Release 编译

23.每次在 VC 环境下运行程序时都要求重新编译(2008.2.28)
问题:不管是否已经全部编译过,都有如下的提示:
One or more files are out of date or do not exist.
These files need to be built:
/COMPANY/其他项目/印刷项目/PrintMBW_Workspace/Execute/PrintMBW.exe
./Release/MyImageWnd.obj
<more files...>
Would you like to build them?
解决:原因是由于代码文件有日期比当前日期还要晚,导致编译器认为 obj 文件不是最新的,所以要求重新编译,解决方法是把那些文件的修改日期改为当前日期即可。

24.类成员函数指针计算不准的问题(2008.5.30 陆宽发现)
typedef char (CMyClass::*MyFunc)();
MyFunc *pFuncList=new MyFunc[16];
这段代码应该创建一个长度为16的MyFunc类型的类成员函数指针数组,实际长度为64字节。但是创建的结果,是生成了一个实际长度为16字节的数组。将类型char替换为void,实际长度变成0字节,替换为int,实际长度为64字节,替换为double,实际长度为128字节。也就是说,vc编译器将返回值的长度误当作函数指针的长度了。但是sizeof(MyFunc)确实等于4。
如果用普通函数指针类型,去掉类型中的CMyClass::,则一切正常。
我认为这是vc编译器的一个严重bug。但是因为这样的语法一般只有框架代码中才会用到,在实际代码中较少出现,所以该bug很难被发觉。
解决:
分配普通的int类型数组,将返回的数组强制转换为MyFunc *类型即可。
MyFunc *pFuncList=(MyFunc *)new int[16];
不知道新版VC中是否已经解决了此bug。

25.类成员函数指针的大小问题(2008.6.19 陆宽发现)
class CTestParentClass{
public:
 CTestParentClass(){}
 virtual void Call()=NULL;
};
class CTestChildClass : public CTestParentClass, CString{
public:
 CTestChildClass() {}
 virtual void Call(){
  void (CTestChildClass::*p)()=MyFunc;
  TRACE("size=%d/n", sizeof(p));
 }
};
调用一下Call函数看看,指针的长度是8字节。

 

 

转载请注明出处

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值