游戏开发论坛

 找回密码
 立即注册
搜索
查看: 7227|回复: 14

帮助debug的一些工具类,希望大家共同探讨和完善。

[复制链接]

5

主题

26

帖子

26

积分

注册会员

Rank: 2

积分
26
发表于 2003-9-27 15:21:00 | 显示全部楼层 |阅读模式
/*+++++++++++++++++++++++++++++++++++++++++++++
        File:        CObject.h
        Desc:        祖先类
        author: zonghongbin
        time:        2003.8
+++++++++++++++++++++++++++++++++++++++++++++*/
#ifndef COBJECT_H
#define COBJECT_H

//-----------------------------------------------------------------------------
// 头文件
//-----------------------------------------------------------------------------
#include <windows.h>
#include <typeinfo.h>

//-----------------------------------------------------------------------------
// 常量
//-----------------------------------------------------------------------------
INT const        MAX_BUFFER = 4096;

//-----------------------------------------------------------------------------
// 宏
//-----------------------------------------------------------------------------
#define                SAFE_DELETE(p)  { if (p) { delete (p);     (p)=NULL; } }
#define                SAFE_RELEASE(p) { if (p) { (p)->Release(); (p)=NULL; } }
#define                SAFE_DELOBJ(p)  { if (p) { DeleteObject(p); (p)=NULL; }

//添加对象类型到m_szObjectString中
#define                ADD_CLASS()                                                                                                \
                        {                                                                                                                \
                                CHAR buf[MAX_BUFFER]="";                                                        \
                                wsprintf(buf,"Ojbect=%s\r\n",typeid(*this).name());        \
                                strcat(m_szObjectString, buf);                                                \
                        }

       
//添加整数型属性到m_szObjectString中
#define                ADD_INT(propname, propvalue)                                \
                        {                                                                                        \
                                CHAR buf[MAX_BUFFER]="";                                \
                                wsprintf(buf,"=%d\r\n",propvalue);                \
                                strcat(m_szObjectString, propname);                \
                                strcat(m_szObjectString, buf);                        \
                        }

//添加字符型属性到m_szObjectString中
#define                ADD_STRING(propname, propvalue)                                \
                        {                                                                                        \
                                CHAR buf[MAX_BUFFER]="";                                \
                                wsprintf(buf,"=%s\r\n",propvalue);                \
                                strcat(m_szObjectString, propname);                \
                                strcat(m_szObjectString, buf);                        \
                        }

//添加BOOL型属性到m_szObjectString中
#define                ADD_BOOL(propname, propvalue)                                \
                        {                                                                                        \
                                CHAR buf[MAX_BUFFER]="";                                \
                                propvalue == FALSE ? wsprintf(buf,"=FALSE \r\n") :        wsprintf(buf,"=TRUE \r\n");        \
                                strcat(m_szObjectString, propname);                \
                                strcat(m_szObjectString, buf);                        \
                        }

//添加对象类型的属性到m_szObjectString中(指针地址)
#define                ADD_OBJECT(propname, propvalue)                                \
                        {                                                                                        \
                                CHAR buf[MAX_BUFFER]="";                                \
                                propvalue == NULL ? wsprintf(buf,"=NULL \r\n") :        wsprintf(buf,"=%d \r\n",propvalue);        \
                                strcat(m_szObjectString, propname);                \
                                strcat(m_szObjectString, buf);                        \
                        }

//添加开始标记到m_szObjectString中
#define                BEGIN_OF_ADD                                                                                        \
                        {                                                                                                                \
                                CHAR buf[MAX_BUFFER]="";                                                        \
                                wsprintf(buf," ------------- %s Properties -------------\r\n",typeid(this).name());        \
                                strcat(m_szObjectString, buf);                                                \
                        }

//-----------------------------------------------------------------------------
// 类定义
//-----------------------------------------------------------------------------
class CObject;

class CObject
{
protected:
        CHAR m_szObjectString[MAX_BUFFER];        //ToString函数使用的字符缓冲区

public:

   
//-----------------------------------------------------------------------------
// 构造函数与析构函数
//-----------------------------------------------------------------------------
        CObject();
    virtual ~CObject();

//-----------------------------------------------------------------------------
// 重载函数
//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
// 其他函数
//-----------------------------------------------------------------------------
        virtual CHAR *ToString();


};

#endif //COBJECT_H








/*+++++++++++++++++++++++++++++++++++++++++++++
        文件:        CObject.cpp
        描述:
        作者:        zonghongbin
        时间:        2003.8
+++++++++++++++++++++++++++++++++++++++++++++*/

#include "CObject.h"


/*========================================================================
名称:        构造函数
描述:        初始化成员变量
返回值:无       
========================================================================*/
CObject::CObject()
{
        strcpy(m_szObjectString,"");
}

/*========================================================================
名称:        析构函数
描述:       
返回值:无       
========================================================================*/
CObject::~CObject()
{
}

/*========================================================================
名称:        ToString
描述:        初始化成员变量
返回值:无       
========================================================================*/
CHAR *CObject::ToString()
{
        strcpy(m_szObjectString,"");
       
        ADD_CLASS();
       
        return m_szObjectString;
}







/*+++++++++++++++++++++++++++++++++++++++++++++
        File:        CUtil.h
        Desc:
        author: zonghongbin
        time:        2003.8
+++++++++++++++++++++++++++++++++++++++++++++*/
#ifndef CUTIL_H
#define CUTIL_H

//-----------------------------------------------------------------------------
// 头文件
//-----------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
#include <time.h>
#include <typeinfo.h>

#include "ddutil.h"
#include "CObject.h"

//-----------------------------------------------------------------------------
// 常量
//-----------------------------------------------------------------------------
INT const SCREEN_WIDTH = 640;
INT const SCREEN_HEIGHT = 480;


//-----------------------------------------------------------------------------
// 宏
//-----------------------------------------------------------------------------

//以下为wsprintf版日志处理宏,注意有1024字节限制
#define                LOG(x) { CUtil:og(x, "log.txt", __FILE__, __LINE__); }
#define                LOG1(s,a) { CHAR szLogBuffer[MAX_BUFFER]; wsprintf(szLogBuffer,s,a);  LOG(szLogBuffer); }
#define                LOG2(s,a,b) { CHAR szLogBuffer[MAX_BUFFER]; wsprintf(szLogBuffer,s,a,b);  LOG(szLogBuffer); }
#define                LOG3(s,a,b,c) { CHAR szLogBuffer[MAX_BUFFER]; wsprintf(szLogBuffer,s,a,b,c);  LOG(szLogBuffer); }
#define                LOG4(s,a,b,c,d) { CHAR szLogBuffer[MAX_BUFFER]; wsprintf(szLogBuffer,s,a,b,c,d);  LOG(szLogBuffer); }

//以下为wsprintf版throw处理宏,注意有1024字节限制
#define                THROW(x) { LOG(x); throw x;  }
#define                THROW1(s,a) { LOG1(s,a); throw s; }
#define                THROW2(s,a,b) { LOG2(s,a,b); throw s; }
#define                THROW3(s,a,b,c) { LOG3(s,a,b,c); throw s; }
#define                THROW4(s,a,b,c,d) { LOG4(s,a,b,c,d); throw s; }

#define                TIMELOG1  LARGE_INTEGER nLogStartTime,nLogEndTime; QueryPerformanceCounter(&nLogStartTime);
#define                TIMELOG2  QueryPerformanceCounter(&nLogEndTime); LOG2("耗时 %d CPU时间单位 计 %d 毫秒",nLogEndTime.LowPart - nLogStartTime.LowPart, CUtil::TimeUp(nLogStartTime));
                       
                       
//-----------------------------------------------------------------------------
// 类定义
//-----------------------------------------------------------------------------
class CUtil;

class CUtil : public CObject
{
protected:
       
public:
//-----------------------------------------------------------------------------
// 构造函数与析构函数
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// 重载函数
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// 其他函数
//-----------------------------------------------------------------------------
        static INT TimeUp(LARGE_INTEGER startTime);       
        static VOID CUtil::Log(        CHAR *szBuffer,                //测试数据
                                                        CHAR *szFile,                //指定的文件
                                                        CHAR *szSrcFile,        //源程序文件,使用__FILE__
                                                        INT nLine                        //源程序行,使用__LINE__
                                                        );
        static struct tm *NowDateTime();

};

#endif //CUTIL_H




/*+++++++++++++++++++++++++++++++++++++++++++++
        File: CUtil.cpp
        Desc:
        author: zonghongbin
        time:        2003.8
+++++++++++++++++++++++++++++++++++++++++++++*/

#include "CUtil.h"


/*========================================================================
名称:        TimeUp
描述:        判断给定的时间段是否耗完
返回值:已过去的时间毫秒数
========================================================================*/
INT CUtil::TimeUp(LARGE_INTEGER startTime //设定的开始时间
                                  )
{
        LARGE_INTEGER endTime;  
        LARGE_INTEGER passTime;  //结果
    LARGE_INTEGER Frequency;   
        LARGE_INTEGER nCountPerMillSecond;
       

        //取一秒的记数
        QueryPerformanceFrequency (&Frequency);
        nCountPerMillSecond.QuadPart = Frequency.QuadPart/1000;
       
        QueryPerformanceCounter( &endTime );             
        passTime.QuadPart = (endTime.QuadPart - startTime.QuadPart)/nCountPerMillSecond.QuadPart;
        return passTime.LowPart;

}

/*========================================================================
函数名:        Log
功能:                把测试数据写入文件
返回值:        无
========================================================================*/
VOID CUtil::Log(        CHAR *szBuffer,                //测试数据
                                        CHAR *szFile,                //指定的文件
                                        CHAR *szSrcFile,        //源程序文件,使用__FILE__
                                        INT nLine                        //源程序行,使用__LINE__
                                        )
{
        struct        tm *newtime;
        CHAR        szLog[MAX_BUFFER];
        CHAR        szTitle[MAX_BUFFER];

        newtime=NowDateTime();

        //wsprintf最多可以处理1024bytes
        wsprintf(szTitle,"\r\n[%04d-%02d-%02d %02d:%02d:%02d]\r\nFile=%s\r\nLine=%d\r\n",
                newtime->tm_year,newtime->tm_mon,newtime->tm_mday,newtime->tm_hour,newtime->tm_min,newtime->tm_sec,
                szSrcFile,nLine);
        strcpy(szLog,"\r\n####################################################");
        strcat(szLog,szTitle);
        strcat(szLog,szBuffer);
        strcat(szLog,"\r\n");       
       
        //写日志
       
        FILE *f = NULL;
        f = fopen(szFile,"a");
        if( f == NULL)
        {
                throw "打开文件失败。";
                return;
        }
        CHAR *p;
        p = szLog;
        while( fputc(*(p++),f) != 0 ) {;}
        fclose(f);
}

/*========================================================================
函数名:        NowDateTime
功能:                获取本机当前日期和时间
返回值:        无
========================================================================*/
struct tm *CUtil::NowDateTime()
{
        struct        tm *newtime;
        time_t        long_time;
        INT                year=0,
                        mon=0;

        /*取当前时间并显示*/
        time(&long_time);               
        newtime = localtime(&long_time);        
        year = newtime->tm_year + 1900;
        mon = newtime->tm_mon + 1;
       
        newtime->tm_year = year;
        newtime->tm_mon = mon;
        return newtime;
}

21

主题

111

帖子

126

积分

注册会员

Rank: 2

积分
126
QQ
发表于 2003-9-27 15:39:00 | 显示全部楼层

Re:帮助debug的一些工具类,希望大家共同探讨和完善。

真后悔VC没有好好啃

8

主题

716

帖子

716

积分

高级会员

Rank: 4

积分
716
发表于 2003-9-28 09:10:00 | 显示全部楼层

Re:帮助debug的一些工具类,希望大家共同探讨和完善。

代码缺乏美感

2

主题

28

帖子

28

积分

注册会员

Rank: 2

积分
28
QQ
发表于 2003-11-4 17:06:00 | 显示全部楼层

Re: 帮助debug的一些工具类,希望大家共同探讨和完善。

首先,那么多个LOG的宏有什么实际应用吗?把其中定义的szLogBuffer提取出来作为全局变量或Log专用变量会不会更节省?

然后,向log文件写入为什么要用fputc一个一个字节写入而不用fwrite和strlen配合写入?有特殊意义吗?

而且,用您的算法,while( fputc(*(p++),f) != 0 ) {;},循环会在把字符串的结束符0x00写入后才停下来,log文件中每一条记录结尾都成了0D 0D 0A 00,也就是换行后多了一个00。

接着,既然wsprintf说明缓冲区不能大于1024字节,为什么您定义MAX_BUFFER为4096?而wsprintf跟sprintf有什么区别吗?我在MSDN中找到wsprintf对缓冲区1024字节的规定但是没有对sprintf的缓冲区作大小规定呢,是不是用sprintf更好呢?

另外,fopen中的参数用a,但是MSDN的文档中说a跟a+的差别在于a不删除原有的EOF记号,以致DOS的type指令只会显示出最初的未append的内容。转用a+会不会更稳妥?

还有,wsprintf中使用\r\n,但是在log文件中就变成了0D 0D 0A,有一个0D多余了,以致UE询问是否转换成DOS格式。是不是单用\n就可以了?

最后,还有一个菜菜的问题:为什么用的都是Windows的大写的CHAR、INT、VOID?而不用语言提供的char, int和void?有什么特殊的意义吗?

麻烦楼主解答一下~ [em10]

59

主题

1104

帖子

1199

积分

金牌会员

Rank: 6Rank: 6

积分
1199
发表于 2003-11-4 17:13:00 | 显示全部楼层

Re:帮助debug的一些工具类,希望大家共同探讨和完善。

#define ADD_CLASS() \
{ \
CHAR buf[MAX_BUFFER]=""; \
wsprintf(buf,"Ojbect=%s\r\n",typeid(*this).name()); \
strcat(m_szObjectString, buf); \
}

59

主题

1104

帖子

1199

积分

金牌会员

Rank: 6Rank: 6

积分
1199
发表于 2003-11-4 17:14:00 | 显示全部楼层

Re:帮助debug的一些工具类,希望大家共同探讨和完善。

#define ADD_CLASS() \
{ \
CHAR buf[MAX_BUFFER]=""; \
wsprintf(buf,"Ojbect=%s\r\n",typeid(*this).name()); \
strcat(m_szObjectString, buf); \
}

你真要这么写,随便就可以攻击你的代码。
连个长度检查都没有。

5

主题

26

帖子

26

积分

注册会员

Rank: 2

积分
26
 楼主| 发表于 2003-11-4 21:07:00 | 显示全部楼层

Re:帮助debug的一些工具类,希望大家共同探讨和完善。

说来惭愧,公司一忙,我的业余时间都得搭到工作上了(我的工作主要是做物流MIS),所以自己的这点爱好(指游戏编程)也只有牺牲一下了

终于有朋友回贴交流技术问题,我十分的感激!!!
今晚有些空闲,大家讨论讨论不亦乐乎

Re Mal 先:
1.关于LOG宏的问题
LOG的主要目的是在不影响交互性的前提下(如不用跳出MessageBox),跟踪对象的状态:
如LOG(m_pPlayerTank->ToString());在运行程序时可以产生类似于下面的日志:
####################################################
[2003-11-04 20:08:54]
File=F:\游戏工作室\ZHB\demo\CStage.cpp
Line=398
Ojbect=class CPlayerTank
------------- class CMovable * Properties -------------
m_x=220
m_y=156
m_width=32
m_height=32
m_nStatus=1
m_nDirection=3
m_nSpeed=2
m_nPassRate=20
m_nBlastFrame=0
m_nBlastFrameCount=0
m_bBlast=FALSE
------------- class CTank * Properties -------------
m_pSurfaceArmor[0]=9184448
m_pSurfaceArmor[1]=9184304
m_pSurfaceArmor[2]=9184160
m_pSurfaceArmor[3]=9184016
m_pSurfaceArmor[4]=9183872
m_pSurfaceUp=9182368
m_pSurfaceDown=9182080
m_pSurfaceLeft=9181936
m_pSurfaceRight=9182224
m_pSurfaceBlast[0]=9181072
m_pSurfaceBlast[1]=9180928
m_pSurfaceBlast[2]=9180784
m_pSurfaceBlast[3]=9180640
m_bShootStatus=TRUE
m_nShootTimeSpan=600
m_nArmor=1
m_nBulletPower=1
m_nBulletSpeed=3
------------- class CPlayerTank * Properties -------------
m_pDisplay=9176416
m_pSurfaceLucky=9185024
m_nLuckyWidth=16
m_nLuckyHeight=16
m_nLuckyBeginTime.HighPart=1
m_nLuckyBeginTime.LowPart=-1941039504
m_nLuckyTime=2
m_nLuckyStatus=1

不用全局变量的目的是为了降低代码偶合度。
另外1024字节的限制是针对wsprintf的,而strcat无此限制,所以对于第一个LOG(x)宏也就无此限制,我使用LOG(x)的频率较高,出于方便(我的有些类属性的长度较大如地图)使用了4096。

2.关于fputc的问题
用fputc主要是个人习惯问题(可能不是什么好习惯:)),你完全可以用其他的方法如:iostream等。

3.关于wsprintf的问题
因为我第一次学习C语言时接触的格式化字符串的函数就是wsprintf,所以就沿用至今,因为一直够用,所以没有考虑其他方法,这也算一个习惯问题吧。
另外关于wsprintf中使用\r\n,因为我主要使用记事本查看日志,所以回车与换行都要,使用UltraEdit和Word、写字板时由于对文本格式要求有些差别,你可以都试试,不过记事本是最平民化:)的东西,所以我一般都在wsprintf中使用\r\n。

4.关于fopen的参数"a"和"a+"
“a”主要用于只写操作,因为是只写,没有读要求,所以在fclose之前,不必每次都调整EOF,这样可以使效率高些;而"a+"主要用于写后读操作,这样,因为每次写文件后(此时还未执行fclose)又要读文件,所以必须调整EOF使读文件信息时完整。

5.关于CHAR、INT、VOID的问题
因为CHAR、INT、VOID都是宏,所以可以通过#ifdef等宏对其实际的数据类型进行控制,这样适应性会好些。不过即时写成int等也问题不大,如果我们大家都坚持不写宏,工具开发商也会考虑来迎合我们的,毕竟客户是上帝嘛:)

5

主题

26

帖子

26

积分

注册会员

Rank: 2

积分
26
 楼主| 发表于 2003-11-4 21:17:00 | 显示全部楼层

Re: Re:帮助debug的一些工具类,希望大家共同探讨和完善。

因为考虑到一般类名不会超出MAX_BUFFER的长度,而且即使超过,wsprintf也只是截断,不会引发异常,所以未做长度检测。不知您所说的攻击代码是什么意思?

2

主题

28

帖子

28

积分

注册会员

Rank: 2

积分
28
QQ
发表于 2003-11-5 02:11:00 | 显示全部楼层

Re:帮助debug的一些工具类,希望大家共同探讨和完善。

  哦,原来如此……其实我是在设计游戏中的日志系统,所以找您的设计参考一下的,最初想法只是集中于最后的部分,LOG宏跟Log函数实现,没有全局地看(一大堆宏的确很……眼花)。原来设计目的是把某时刻的某对象属性都记录下来啊,怪不得搞了个象JAVA的ToString函数出来。诶?把根对象命名为CObject跟MFC混合使用时会不会冲突的吖?继续探讨探讨……

  1、耦合性吗,嗯……但是你如果把这个调试类单独作为一个模块,把szLogBuffer[MAX_BUFFER];作为CUTIL类的一个公有成员,而调用者都只是你定义的宏(它们都在这个模块相关的头文件里定义是吧?),那么实际上在其他模块中调用你写的宏来调用它,可能出现的最坏情况就是:当你修改了对szLogBuffer的定义时,所有调用LOG宏的源代码都要重新编译。但是这跟现在有什么两样吗?现在的情况是:除非wsprintf的实现改变了,如希望其第一个参数不是LPTSTR,此时需要修改LOG宏,同时所有使用LOG宏的代码都要重新编译。但是,wsprintf在可预见的短期内都不会改变其形参的定义,因此在这段时间内客户代码都是可以安枕无忧的。同时你也很确定,你的LOG(x)宏的x接收的就是现在的wsprintf的首参数的类型,因此你的CUTIL类中关于Log的部分接收的参数在这段时期内都将是不变的。同理可得,如果把szLogBuffer定义为CUTIL类成员用于承接LOG宏调用中的字符串合并操作,在可预见的时间内都是不会改变它的定义的。同时(我把自己说得快晕倒了……@_@),现在的实现方式是在每一处插入LOG的地方都定义一块4096Byte大小的空间,会不会造成代码要求的内存太多(我不清楚这些编译时确定的局部生命期变量的内存是怎么安排的,栈空间分配是吧?我只是怀疑)而间接在某些条件下成为某些异常情况的始作俑者呢?(C++的内存分配机制没学通,说错了别怪我,请纠正。)

  2、我主要是想指出,按照您的fputc循环条件,在换行后还会把空字符0写进文件,比较象是一处疏漏。我觉得用fwrite一次性写入会比较简洁咯,而且不需要临时变量的支持。

  3、哦……但是实际情况是写入成为 0D 0D 0A了,也就是说\n已经把回车跟换行都做了,不必分开写。我在NotePad中打开\r\n输出的文本时看到是蛮正常的,可能是它自动过掉了,但在UE中就明显多了个问号?在行尾(控制符所以显示不出来?)。

  4、如果按照你用fputc一个个字符写进去的话,的确倘若每次都移动EOF标记位置是挺那个的。我指的问题主要是MSDN说:
“The "a" mode does not remove the EOF marker before appending to the file. After appending has occurred, the MS-DOS TYPE command only shows data up to the original EOF marker and not any data appended to the file. The "a+" mode does remove the EOF marker before appending to the file. After appending, the MS-DOS TYPE command shows all data in the file. The "a+" mode is required for appending to a stream file that is terminated with the CTRL+Z EOF marker.”
  大意是说a模式在添加到最尾前不移除EOF标记(也没说事后到底有没有把新的EOF放到正确位置去…ft...),而又说MS-DOS的TYPE无法看到a模式添加的内容云云。一直用NotePad打开应该是没问题的(理论上也永远不会回到DOS去TYPE不是吗? ),只是有个疑问罢了。

  5、哦!这样说来倒该是多多使用这种数据类型的宏以提高移植性了……只是没有了高亮显示类型,有点不习惯,而且有时看着LPCTSTR这样的数据类型不禁发一下呆才反应过来……=^o^=

59

主题

1104

帖子

1199

积分

金牌会员

Rank: 6Rank: 6

积分
1199
发表于 2003-11-5 09:37:00 | 显示全部楼层

Re: Re: Re:帮助debug的一些工具类,希望大家共同探讨和完善

zonghongbin: Re: Re:帮助debug的一些工具类,希望大家共同探讨和完善。

因为考虑到一般类名不会超出MAX_BUFFER的长度,而且即使超过,wsprintf也只是截断,不会引发异常,所以未做长度检测。不知您所说的攻击代码是什么意思?


大侠,你自己去试试:
class aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...; // 此处超过4096.
然后写你的buf,马上就会溢出,然后应该会有个segmentation fault,然后从segmentation fault可以找出你wsprintf的地址,然后可以修改你该函数的返回地址,将其指到一串你自己事先准备好的代码。

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2025-2-24 02:07

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表