VC程序调试的方法

TRACE 使用方法与printf完全一致,在output框中输出调试信息

ASSERT 接收一个表达式,如果表达式为true,则无动作,否则终端当前程序执行,对于系统中出现这个宏导致的中断,应该认为函数调用未能满足系统的调用此函数的前提条件,例如,对于一个没有创建的窗口调用setwindowtext

VERIFY和ASSERT功能类似,所不同的是,在Release版本中,ASSERT不计算表达式的值,而VERIFY计算表达式的值

几个关于C/C++调试用到的函数

1调用栈系列

下面是函数原型

#include "execinfo .h"
int backtrace(void **buffer, int size);
char **backtrace_symbols(void *const *buffer, int size);
void backtrace_symbols_fd(void *const *buffer, int size, int fd);

(1)backtrace用来获取当前程序的调用栈,把结果存在buffer中。通常,我们用gdb调试程序,设置合适的断点,停下来之后,用backtrce命令,就可以看到当前的调用栈,但是有时候,用到条件断点的时候。gdb的功能就没有程序本身的功能强大了,这个时候就可以考虑在程序中调用backtrace函数,来获取调用栈。

(2)backtrace_symbols把用backtrace获取的调用栈转换成字符串数组,以字符串数组的形式返回,使用这需要在外面释放返回的字符串数组所占用的内存

(3)backtrace_symbols_fd把用backtrace获取的调用栈信息写到fd所指定的文件中

void * __builtin_return_address (unsigned int level)

这个函数用来得到当前函数,或者调用它的函数的返回地址,得到这个地址后,通过gdb反汇编,便可得到调用函数相关的信息,这也是在应用中获取调用栈的一种fangfa。

2内存分配释放

#include "malloc .h"
size_t malloc_usable_size((void *__ptr));

这个函数的用法是返回调用malloc后实际分配的可用内存的大小,我们知道在c++中,operator new()可以重载各种各样的版本,可以传入调用的相关信息来跟踪内存分配情况。但是operator delete()却只有两种形式,不能随意重载,尤其是全局的operator delete(),只有一种版本,这个时候就比较痛苦了,究竟释放了多少内存,这时候malloc_usable_size()这个函数就有用武之地了,调用它就可以获取当前释放的内存大小,那么在new中也请用他来统计开辟的内存,这样才能对应起来,因为在调用malloc时很多时候实际分配内存会比用户申请的要大一些,所以如果两边的统计方法对应不起来的话,统计结果也有比较大的判别

C++内存分配与管理

1函数

(1)operator new function

void * ::operator new(size_t);	                //Global
void * class-name::operator new(size_t); 	//Class

上面是C++中operator new function的原型,一个是全局类型,一个的类成员类型,全局类型的operator new 函数在下面两种情况下被调用:一种是在分配C++内建类型的动态内存时,一种是在分配用户自己定义的operator new函数,那么用户在用new申请该类型的动态内存时,便会调用该类型的成员函数operator new,而不是全局的operator new。

另外,我们注意到,上面的原型中函数的返回值void* 类型,第一个参数为size_t类型,这个是C++编译要求的,如果要自己重载operator new函数,返回值必须为void* 类型,第一个参数必须为size_t类型,否则,编译器会返回如下错误信息:

error: ‘operator new’ takes type ‘size_t’ (‘unsigned int’) as first parameter

这里需要注意的一点是,我们可以利用operator new function可以重载的特点,可以通过参数传入一些额外的信息,来调试程序,检测内存泄露,比如,我们可以向下面这样重载,传调用处的行号,函数名,这样就可以跟踪内存的分配

void * operator new(size_t unSize, int nLine, const char * pFunc)
{
    prinft("Line: %d, Func: %s, allocate %u byte(s)\n", nLine, pFunc, unSize);
    return malloc(unSize);
}

(2)operator delete function

void operator delete( void * );
void operator delete( void *, size_t );

上面是operator delete function的原型,operator delete function也有全局和类成员的两种,这压力需要注意,一个类只能有一个operator delete function作为其成员函数,而且必须为上面两种中的其中一种,没有其他的形式,如果一个类实现了自己的operator delete function成员函数,那么在释放该类型的内存时,编译器便会调用成员operator delete function,而不是全局的。

上面两种原型,第一种在调用的时候,编译器会把释放的内存的首地址传入,第二种在调用的时候,编译器会把要释放的内存的首地址和大小都传入,因此,可以利用这一特性,如果我们在基类中实现第二种形式的operator delete function的成员函数,那么便可以之来释放子类类型的内存。

2 运算符

(1)new operator

[::] new [placement] new-type-name [new-initializer]
[::] new [placement] ( type-name ) [new-initializer]

上面是new operator 的原型,在c++中,动态内存的分配,通常都是调用new operator来完成的,利用new operator来分配动态内存,编译器要做下面两项工作:

a. 调用operator new function 分配内存

b. 调用构造函数来进行初始化

下面来说一说new operator的原型中各部分到底是干什么的:

placement:如果你重载了operator new function,placement可以用来传递额外的参数

type-name:指定要分配的内存类型,可以是内建类型,也可以是用户自定义类型

new-intializer:指定要分配后的内存的初始化参数,也就是构造函数的参数。这里需要注意一点,在分配一个对象的数组类型的内存时,不能够指定初始化参数:换言之,想要分配一个对象的数组类型的内存,该对象必须有缺省构造函数

(2)delete operator

[::] delete cast-expression
[::] delete [ ] cast-expression

上面是delete operator的原型,第一种是用来释放普通的对象类型的内存,第二种是用来释放对象的数组类型的内存,在C++中,用new operator分配的动态内存,必须调用delete operator来释放,通常用delete operator 释放内存编译器要做下面两箱工作:

a 调用对象析构函数来析构对象

b 调用operator delete function 来释放内存

3关于new/delete使用过程中一些需要注意的点

(1)如何区别operator new/ delete function与new/delete operator?

通过上面的讲述,不难看出,我们分配/释放动态内存,调用的是new/delete operator, 而在调用new/delete的过程中,编译器会自动调用operator new/delete function来完成实际的内存分配/释放的工作

(2) 用delete operator去释放一块不是由new operator释放的内存,结果是不可预料的,因此,切记,operator new与operator delete一定要配对使用,这是写好程序的基础

(3) new operator调用失败会抛出std::bad_alloc异常,前提是你没有自己重载对应的operator new function;delete operator失败,常见的原因是多次delete同一块内存

(4) 如果一块内存被delete后,再对它解引用(Dereference),结果也是不可预测的,很可能导致程序崩溃

(5) delete一个空(NULL)指针是安全的,没有任何害处的

(6) 类成员类型的operator new/delete函数必须为静态(static)函数,因此它们不能为虚函数(virtual function),也遵守public, protected, private的访问权限控制

时间: 2024-10-12 09:45:06

VC程序调试的方法的相关文章

.NET应用程序调试—原理、工具、方法

阅读目录: 1.背景介绍 2.基本原理(Windows调试工具箱..NET调试扩展SOS.DLL.SOSEX.DLL) 2.1.Windows调试工具箱 2.2..NET调试扩展包,SOS.DLL.SOSEX.DLL 2.3.调试系统的基本流程及架构(.NETDAC概念.mscordacwks.dll) 2.4.VisualStudio中集成扩展调试(更加细粒度的调试程序) 3.调试程序类型(客户端程序.服务端程序) 4.调试方式及场景 4.1.本机调试(Attach Process,调试器启动

Windows程序调试系列: 使用VC++生成调试信息 转

Windows程序调试系列: 使用VC++生成调试信息 ZhangTao,[email protected], 译自 “Generating debug information with Visual C++”,Oleg Starodumov 出处: http://www.cnblogs.com/itrust/archive/2006/08/17/479603.aspx 引子 当我们使用调试器来调试程序时,我们希望能够单步调试到源代码中,在代码中设置断点,观察变量的值(包括用户自定义的复杂类型的

嵌入式linux应用程序调试方法

嵌入式linux应用程序调试方法 四 内存工具 17 4.1 MEMWATCH 17 4.2 YAMD 22 4.3 Electric Fence 24 五 C/C++代码覆盖.性能profiling工具 24 5.1 用gcov来测试代码覆盖率 25 5.2 使用gprof来优化你的C/C++程序 35 四 内存工具 您肯定不想陷入类似在几千次调用之后发生分配溢出这样的情形. 许多小组花了许许多多时间来跟踪稀奇古怪的内存错误问题.应用程序在有的开发工作站上能运行,但在新的产品工作站上,这个应用

【转】WinDbg调试器:启动程序时自动连接调试器方法

当我们调试服务进程或子进程时,无法直接用调试加载进程的方式启动,此时需要在启动程序时自动连接调试器方法: 第一步:注册表展开到HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options路径下: 第二步:在Image File Execution Options上鼠标右键,新建"项",项名为你要调试的程序,比如 test.exe: 第三步:在项名上,右键,新建字符

在虚拟机调试反VM程序的解决方法

在虚拟机调试反VM程序的解决方法 只针对VMware ,只要在.vmx文件中加入以下命令就可以了 isolation.tools.getPtrLocation.disable = "TRUE"isolation.tools.setPtrLocation.disable = "TRUE"isolation.tools.setVersion.disable = "TRUE"isolation.tools.getVersion.disable = &q

VC利用调试寄存器实现硬件断点源码

[文章标题]:VC利用调试寄存器实现硬件断点源码 [文章作者]:yhswwr(SilenceRet) [作者QQ]:3412259 [编写语言]:C++ [使用工具]:VS2008.VC++9 [本文链接]:http://bbs.pediy.com/showthread.php?p=1122838 [参考链接]:http://bbs.pediy.com/showthread.php?t=107515 [作者声明]:只是感兴趣,没有其他目的.失误之处敬请诸位大侠赐教!(当前行剽窃自justhxy)

也来说说关于未在本地计算机上注册“VFPOLEDB.1”的程序的解决方法

大家都知道VFP是一个非常古老的数据库.但是,还有一些单位用到这些数据库. 前段时间,也做了一个关于DBF数据导出的功能的测试.程序以前有同事写好了,但当我进行修改调试的时候,问题就出来了. 调试的时候,一切都是正常的,VFPOLEDBSetup.msi这个肯定得先安装. 但是,架设到IIS上之后,就不行了,出现未在本地计算机上注册"VFPOLEDB.1"的程序这样的错误. 由于之前也没碰过DBF文件导入导出或者操作方面的问题,所以,第一想到的是百度. 百度上面,当然有好多答案,基本上

Xcode5.1离线下载安装及使用iOS5模拟器进行开发调试的方法

Xcode5.1默认不支持iOS5版本的模拟器开发调试,在OS X Mavericks(10.9.x)下默认只能支持iOS6.1及以上版本的模拟器,在OS X Mountain Lion(10.8.x)下默认只能支持iOS6.0及以上版本的模拟器进行开发和调试,在此条件之下的版本只能使用硬件设备进行开发调试.虽然现在低版本的iOS设备越来越少了,但是有时客户的需求可能会要求我们一定要兼容iOS5(或更低版本)及以上版本,如果我们手头找不到低版本硬件设备用于调试或者完全使用硬件设备而没有对应的模拟

微信小程序调试之【不在以下合法域名列表中】

在微信小程序中进行网络通信,只能和指定的域名进行通信.目前,微信小程序提供如下四种类型的网络请求. 普通HTTPS请求(wx.request) 上传文件(wx.uploadFile) 下载文件(wx.downloadFile) WebSocket通信(wx.connectSocket) 目前,无论上述哪一种请求方式,都有次数限制.本文记录的是,我在使用豆瓣论坛API请求时,遇到的错误截图及解决办法.简记如下: 一.问题截图 小程序调试中,遇到如下错误提示: "xxx不在以下合法域名列表中 ,请参