zgpxgame

像作诗一样写程序,像弹琴一样敲代码,像看小说一样读开源

Doom3源码剖析(1)--TypeInfo

TypeInfo模块是Doom3中用于动态类型识别(RTTI)和辅助查错的模块,可以检测类中未初始化变量、打印某种类型的对象中所有成员变量的值,或打印整个程序中所有实体对象(idEntity)的值。在写程序过程中,可能经常会出现一些由于未对成员变量初始化而导致的问题。而这类问题一般在Debug模式下没有问题,在Release版本中偶尔出现,这导致很难定位与问题相关的代码。

    除了检测未初始化的内存,其他方面的应用,可以从TypeInfo.h中的几个函数可以略窥一二。

 /*
=================================================================================== 

    Game Type Info

===================================================================================
*/

// 根据偏移取得变量名
const char * GetTypeVariableName( const char *typeName, int offset );
// 打印某个对象的信息
void PrintType( const void *typePtr, const char *typeName );
// 将某对象值写入文件
void WriteTypeToFile( idFile *fp, const void *typePtr, const char *typeName );
// 给某对象的所有变量设定一个初始值
void InitTypeVariables( const void *typePtr, const char *typeName, int value );
// 列举所有类型信息
void ListTypeInfo_f( const idCmdArgs &args );
// 将所有游戏状态(所有idEntity信息)写入文件
void WriteGameState_f( const idCmdArgs &args );
// 比较游戏状态
void CompareGameState_f( const idCmdArgs &args );
// 测试保存游戏
void TestSaveGame_f( const idCmdArgs &args );


经过几天的努力,我将
TypfInfo相关的代码提取出,单独创建了工程文件,并做了简单的代码演示。有爱好的同学可以深入研究。点击这里下载。在工程( vs2010) 中,Example是一个简单的演示程序,idLib是对Doom3源码中idLib的删减版本。TypeInfo是生成GameTypeInfo.h类型信息的控制台工具。

TypeInfo的用法为 typeinfo.exe [source_code_path] [out_file_name]

 

实现:

TypeInfo检测未初始化内存实现原理为,对代码中所有的头文件扫描分析,并将类型中,变量名,变量类型等信息记录生成一个GameTypeInfo.h文件。然后在new一个对象时,会先将这个对象的内存初始化为0xcdcdcdcd。当对象构造完成时,检测对象内存中是否有某值为0xcdcdcdcd,如果有,就通过GameTypeInfo.h中记录的类型,变量名,偏移等信息将未初始化的变量信息打印出来。

将上述过程分为三段内容:1. 解析 2. 生成类型信息 3. 利用类型信息

 

1. 解析:

基本的词法解析在idLib中实现,相关类为idToken, idLexer, idParser

 

2. 生成类型信息

idTypeInfoGen利用idParser来解析代码头文件,记录相关类型信息,类型信息包括:常量,枚举量和类(包括结构体)

 

// 常量信息 
typedef struct {
    const char * name;
    const char * type;
    const char * value;
} constantInfo_t;

// 枚举形变量信息
typedef struct {
    const char * name;
    int value;
} enumValueInfo_t;

// 枚举类型信息
typedef struct {
    const char * typeName;
    const enumValueInfo_t * values;
} enumTypeInfo_t;

// 类成员变量信息
typedef struct {
    const char * type;
    const char * name;
    int offset;
    int size;
} classVariableInfo_t;

// 类的类型信息(包括结构体)
typedef struct {
    const char * typeName;
    const char * superType;
    int size;
    const classVariableInfo_t * variables;
} classTypeInfo_t;

所有信息记录在GameTypeInfo.h中,详细内容可以查阅源代码。

3. 对类型信息的利用

3.1 通过类型名创建实例。在Doom3程序的GamePlay层,主要的类都是从idClass继承下来的,并且在类声明和定义时,通过idTypeInfo记录类型信息,包括记录类之间的父子关系。在类中加入宏CLASS_PROTOTYPE CLASS_DECLARATION来实现。
创建类实例时是这样的:

idTypeInfo *cls;
idClass *obj;
cls = idClass::GetClass( "idPlayer" );
obj = cls->CreateInstance();

 

    3.2 输出未初始化变量的名称。

     idClass中重载了new操作符,以便记录内存的使用量和创建的对象个数,如果需要检测未初始化的内存,还会将内存初始化为0xcdcdcdcd。

void * idClass::operator new( size_t s ) {
    int *p;

    s += sizeofint );
    p = (int *)Mem_Alloc( s );
    *p = s;
    memused += s;
    numobjects++;

#ifdef ID_DEBUG_UNINITIALIZED_MEMORY
    unsigned long *ptr = (unsigned long *)p;
    int size = s;
    assert( ( size & 3 ) == 0 );
    size >>= 2;
    for ( int i = 1; i < size; i++ ) {
        ptr[i] = 0xcdcdcdcd;
    }
#endif

    return p + 1;
}

 

 
    对象创建后,调用
FindUninitializedMemory来检测未初始化的内存

/*
================
idClass::FindUninitializedMemory
================
*/
void idClass::FindUninitializedMemory( void ) {
#ifdef ID_DEBUG_UNINITIALIZED_MEMORY
    unsigned long *ptr = ( ( unsigned long * )this ) - 1;
    int size = *ptr;
    assert( ( size & 3 ) == 0 );
    size >>= 2;
    ptr = ( unsigned long * )this;
    for ( int i = 0; i < size; i++ ) {
        if ( ptr[i] == 0xcdcdcdcd ) {
            const char *varName = GetTypeVariableName( GetClassname(), i << 2 );
            idLib::Warning( "type '%s' has uninitialized variable %s (offset %d)", GetClassname(), varName, i << 2 );
        }
    }
#endif
}
    
    这里通过
 GetTypeVariableName 在类型信息表中查找变量名称。


    3.3打印输出某个实例的所有成员变量值。

 

         代码实现在TypeInfo.cpp文件中,没有仔细研究这段代码实现,就不在这里单列了。

posted on 2012-04-22 20:28 zgpxgame 阅读(3865) 评论(3)  编辑 收藏 引用 所属分类: DOOM3

评论

# re: Doom3源码解读(1)—TypeInfo 2012-04-23 08:49 tb

很不错的算法  回复  更多评论   

# re: Doom3源码解读(1)—TypeInfo 2012-04-23 14:11 嵌入式培训

算法上确实不错,  回复  更多评论   

# re: Doom3源码解读(1)—TypeInfo 2012-04-23 15:59 老鱼

貌似与visual c++编译成debug版本所用的方法类似。不知道是谁先搞出来的。  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理