现在的位置: 首页 > 综合 > 正文

给函数增加debug头

2013年08月06日 ⁄ 综合 ⁄ 共 4748字 ⁄ 字号 评论关闭

      调试程序时,经常需要查看程序的函数调用的流动方向。在PC上很简单,可以F10、F11单步调试查看或者gdb命令行查看。不过实际调试发现,在处理多重继承和虚函数的调用时,vc-express-2008的调试器单步并不能很好的发挥效用【目前还未单独针对这个结论做样例,以后再补上】。而在嵌入式设备上却很难实现单步调试。打印日志就成了很有用的调试方式。然而,在比较庞大的程序里,所有的函数头手动添加调试语句不太现实【自己一字一字码起来的除外,原因大家都懂的^_^】。所以想到了写个小工具,专门在所有的函数头添加调试语句。

      废话少说,上代码:

#include <iostream>  
#include <vector>  
 
using namespace std;  
 
/*******************************************************
功能:对输入的.h、.cpp文件的所有函数头增加打印
条件:考察的代码文件能正常编译通过,本程序不进行文法、语义检查
步骤:
    1、读入文件[简化成申请合适空间一次性读入]
    2、找到函数头[简化成不考虑有额外的宏定义的函数头]
       ①找到所有的不在单引号或者双引号之内的'{'
       ②排除'{'前导[非空和换行的字符]为if()、for()、while()、switch()
       ③排除'{'前导不是')' [不考虑 static / const 修饰函数]
       ③其余均为函数头
    3、在'{'后添加打印:[回车换行]Debug_Func("tagxxx---func:%s,line:%d,file:%s",__FUNCTION__,__LINE__,__FILE__);[回车换行]
*******************************************************/  
 
#define SWITCH_LENGTH 6  
#define FOR_LENGTH 3  
#define WHILE_LENGTH 5  
#define IF_LENGTH 2  
 
#define BUF_SIZE 100000
#define PATH_SIZE 300  
#define DBG_LENGTH 20
 
const char *debugSentence = "\nDebug_Func(\"tagxxx---func:%s,line:%d,file:%s\\n\",__FUNCTION__,__LINE__,__FILE__);" ;  
 
vector<int> debugPlace;//记录每次有效{的位置  
 
void readfile(const char *filename, char *buf)  
{  
    FILE* fp = fopen(filename,"rb");  //改成rb之后正常了...奇怪,明明是txt文件,fread内容不对,多出一段。这个地方很典型。可能c++的文件读写有更好的方式,习惯了c的方式了
    
    if(!fp)  
    {  
        printf("error:no such file");  
        exit(-1);  
    }

    fflush(fp);
    
    int n = fread(buf,sizeof(char),BUF_SIZE,fp);  
    
    fclose(fp);  
}  
 
void writefile(const char *filename,char *buf)  
{  
    FILE* fp = fopen(filename,"wb");  //改成wb之后正常了...不然会在每个行尾多回车换行写入
    if(!fp)  
    {  
        printf("error:no such file");  
        exit(-1);  
    }  
    fwrite(buf,sizeof(char),strlen(buf),fp);  
    fclose(fp);  
}  
 
bool printable(char ch)  
{  
    if(ch >= 'a' && ch <= 'z')  
        return true;  
    if(ch >= 'A' && ch <= 'Z')  
        return true;  
    if(ch >= '0' && ch <= '9')  
        return true;  
    if(ch == ')' || ch == ';')  
        return true;  
    return false;
}  
 
void analy(char *buf)  
{  
    bool sinQuoteFlag = false, douQuoteFlag = false;  
    bool valid = false;  
    int line = 0;
    char chtmp = 0x00;
    int rightSide = 0;
    int placeMark[3] = {-1, -1, -1};//标记位置:分别')'、'('、'('左边第一个可打印字符的位置

    char dbgstring[DBG_LENGTH]="";

    //外层循环,遍历所有字符
    for(int i=2; i < BUF_SIZE; i++)  
    {  
        chtmp = buf[i];
        if(buf[i] == '\n')
            line++;

        //排除单引号和双引号之内的'{',不考虑\'转义的情况和在注释中的情况。然而要能实际中使用,这点无法避免,需要借助编译器的源码。
        if(buf[i] == '\'')  
            sinQuoteFlag = !sinQuoteFlag;  
 
        if(buf[i] == '\"')  
            douQuoteFlag = !douQuoteFlag;  
 
        if(sinQuoteFlag || douQuoteFlag)  
            continue;  

        if(buf[i] == '{')  
        {  
            //调试语句
            for(int k=0;k < DBG_LENGTH-1; k++)
            {
                dbgstring[k]=buf[i+k];
            }
            printf("%d-----%s-----------^",i,dbgstring);

            //调试语句
            //debugPlace.push_back(i+1);
 
            valid = true;
            placeMark[0] = -1;
            placeMark[1] = -1;
            placeMark[2] = -1;
 
            //回溯排除前导非')'  
            for(int j=i-1; j>=0; j--)  
            {  
                if( !printable(buf[j]) )  
                    continue;  

                //')'的位置
                placeMark[0] = j;
                break;
            }

            //未找到,则跳过本次'{'的考察
            if(placeMark[0] < 1 || buf[placeMark[0]] != ')')
                continue;
            else
            {
                //记载多余右括号的数目以方便找到最外层的左括号,回溯考察字符串,遇到一次左括号则减一
                rightSide = 1;
                //排除是for/while/do/switch/关键字  
                for(int k=placeMark[0]-1; k>=1; k--)  
                {  
                    //')'前出现单双引号直接认为不是函数头,不考虑有注释的情况  
                    if( buf[k] == '\'' || buf[k] == '\"')  
                    {  
                        valid = false;  
                        break;
                    }

                    if( buf[k] == ')' )
                        rightSide++;

                    if( buf[k] == '(' )
                        rightSide--;

                    if( rightSide)  
                        continue;

                    //'('的位置
                    placeMark[1] = k;
                    break;
                }
            }

            if(placeMark[1]<=1)  
                continue;

            //回溯排除前导非printable
            for(int l=placeMark[1]-1; l>=0; l--)
            {  
                if( !printable(buf[l]) )
                    continue;  

                //'('左边的第一个可打印字符的位置
                placeMark[2] = l;
                break;
            }
             
            if(placeMark[2] < 0)
                continue;

            if(placeMark[2] >= IF_LENGTH)
            {
                if(buf[placeMark[2]] == 'f' && buf[placeMark[2]-1] == 'i')
                {  
                    if(!printable(buf[placeMark[2]-2]))
                    {
                        continue;
                    }  
                }  
            }  

            if(placeMark[2] >= FOR_LENGTH)  
            {  
                if(buf[placeMark[2]] == 'r' && buf[placeMark[2]-1] == 'o' && buf[placeMark[2]-2] == 'f')  
                {  
                    if(!printable(buf[placeMark[2]-3]))  
                    {
                        continue;
                    }  
                }  
            }  

            if(placeMark[2] >= WHILE_LENGTH)  
            {  
                if( buf[placeMark[2]] == 'e' && buf[placeMark[2]-1] == 'l' &&  
                    buf[placeMark[2]-2] == 'i' && buf[placeMark[2]-3] == 'h' &&  
                    buf[placeMark[2]-4] == 'w' )  
                {  
                    if( !printable(buf[placeMark[2]-5]) )  
                    {  
                        continue;  
                    }  
                }  
            }  

            if(placeMark[2] >= SWITCH_LENGTH)  
            {  
                if( buf[placeMark[2]] == 'h' && buf[placeMark[2]-1] == 'c' &&  
                    buf[placeMark[2]-2] == 't' && buf[placeMark[2]-3] == 'i' &&  
                    buf[placeMark[2]-4] == 'w' && buf[placeMark[2]-5] == 's' )  
                {  
                    if(!printable(buf[placeMark[2]-6]))  
                    {  
                        continue;
                    }  
                }  
            }
            
            if(valid)  
            {  
                debugPlace.push_back(i+1);//换算成从1开始的索引值,也就是到'{'的字符串的长度,包括'{'  
            }
        }//if(buf[i] == '{')
    }//for(int i=0; i<sizeof(buf); i++)
}
 
void edit(char *buf)  
{  
    if(!debugPlace.size())  
        return;  
 
    char tmp[BUF_SIZE];  
    memset(tmp,0,sizeof(tmp));  
    int segLength = 0;  
 
    memcpy( tmp, buf, debugPlace[0]);  
    memcpy( tmp + debugPlace[0], debugSentence, strlen(debugSentence));  
 
    for(unsigned int i=1;i<debugPlace.size();i++)  
    {  
        segLength = debugPlace[i] - debugPlace[i-1] ;  
          
        //拷贝片段
        memcpy( tmp + i * strlen(debugSentence) + debugPlace[i-1] , buf + debugPlace[i-1] , segLength);  
          
        //拷贝调试语句
        memcpy( tmp + i * strlen(debugSentence) + debugPlace[i-1] + segLength , debugSentence, strlen(debugSentence));  
 
        //最后一个调试语句插入之后的,拷贝之后的片段
        if(i == debugPlace.size() - 1)  
        {  
            memcpy(tmp + (i + 1) * strlen(debugSentence) + debugPlace[i] , buf + debugPlace[i], strlen(buf) - debugPlace[i]);  
        }
    }  
    memcpy(buf,tmp,strlen(tmp));  
}  
 
void main(int argc,char *argv[])  
{
    if(argc < 2)
    {  
        printf("The cmd format is : \n\
            dbghead filename1 filename2 filename3 ....");  
        return;  
    }  

    char buf[BUF_SIZE];  
 
    for(int i=1;i<argc;i++)  
    {
        memset(buf,0,sizeof(buf));  
 
        readfile(argv[i],buf);  
 
        analy(buf);  
        edit(buf);  
        
        writefile(argv[i],buf);
    }  
} 

抱歉!评论已关闭.