码迷,mamicode.com
首页 > 其他好文 > 详细

VC程序调试的方法

时间:2014-09-15 22:30:09      阅读:377      评论:0      收藏:0      [点我收藏+]

标签:style   blog   color   io   使用   ar   文件   div   sp   

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的访问权限控制

 

VC程序调试的方法

标签:style   blog   color   io   使用   ar   文件   div   sp   

原文地址:http://www.cnblogs.com/chillblood/p/3973675.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!