给函数增加debug头(一)

本文由 @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);
    }  
} 




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在 Unity 中使用 Debug.DrawLine 画一个圆的代码如下: ``` using UnityEngine; public class DrawCircle : MonoBehaviour { public float radius = 1.0f; // 圆的半径 public int segments = 36; // 圆周分成的线段数 void OnDrawGizmos() { // 从 0 开始计算每个线段的角度 float angle = 0f; // 角度每次增加的量 float angleStep = 360f / segments; // 设置起点 Vector3 lastPoint = Vector3.zero; // 遍历每个线段 for (int i = 0; i <= segments; i++) { // 计算线段的终点 Vector3 point = new Vector3(Mathf.Sin(angle * Mathf.Deg2Rad), 0, Mathf.Cos(angle * Mathf.Deg2Rad)) * radius; // 画出线段 Debug.DrawLine(lastPoint, point, Color.red); // 更新起点和角度 lastPoint = point; angle += angleStep; } } } ``` 使用方法: 1. 创建一个新的 C# 脚本,将上面的代码复制粘贴到脚本中。 2. 将脚本挂载到你想要在其中画出圆的游戏物体上。 3. 在场景视图中,选择游戏物体,并在 Inspector 窗口中调整圆的半径和线段数。 4. 运行场景,可以看到圆已经画出来了。 注意:Debug.DrawLine 只会在 Scene 视图中绘制出来,不会出现在游戏中。 ### 回答2: 在Unity中使用Debug.DrawLine函数画一个圆的代码如下: ```csharp using UnityEngine; public class CircleDrawer : MonoBehaviour { public int numPoints = 100; public float radius = 1f; public Transform center; private void Start() { // 计算圆上的点坐标 Vector3[] points = new Vector3[numPoints]; for (int i = 0; i < numPoints; i++) { float angle = Mathf.PI * 2f * i / numPoints; float x = center.position.x + Mathf.Cos(angle) * radius; float y = center.position.y + Mathf.Sin(angle) * radius; points[i] = new Vector3(x, y, center.position.z); } // 绘制圆上的连线 for (int i = 0; i < numPoints - 1; i++) { Debug.DrawLine(points[i], points[i + 1], Color.red); } // 绘制最后一个点和第一个点之间的连线 Debug.DrawLine(points[numPoints - 1], points[0], Color.red); } } ``` 以上代码创建了一个CircleDrawer类,通过在Unity编辑器中设置numPoints(确定圆上点的数量)和radius(确定圆的半径),并指定一个Transform类型center(确定圆心)来在游戏开始时在场景中绘制一个圆。代码首先计算圆上的点的坐标,然后使用Debug.DrawLine函数来绘制这些点之间的连线,从而形成一个圆。最后一条连线是从最后一个点到第一个点,以闭合圆的形状。在Unity游戏运行时,这个脚本将在场景中绘制一个红色的圆。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值