给函数增加debug头(一)

来源:互联网 发布:中国建筑西北院 知乎 编辑:程序博客网 时间:2024/06/04 01:36

本文由 @lonelyrains 出品,转载请注明出处。 
文章链接: http://blog.csdn.net/lonelyrains/article/details/7719614


      调试程序时,经常需要查看程序的函数调用的流动方向。在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);    }  } 




原创粉丝点击