zoukankan      html  css  js  c++  java
  • __FILE__,__LINE__,__func__ 真好用,DEBUG利器啊!

    我是不喜欢用类似VC下的F5,F10。曾经很喜欢用。被代码逻辑逼的没招了。所以不喜欢用了。

    比如,错误是根据动态数据,产生的行为错误,无论是该写的未写,还是不该写的写了。指针跑飞什么等等,无非就是上述两个错导致。但要找到具体原因,F5,F10根本不够。所以索引不用了。

    这里介绍一下我现在的方法。不过注明这不是LOG。

    一个头文件。大体如下:

     1 #ifndef _debug_H_
     2 #define _debug_H_
     3 
     4 #include <stdlib.h>
     5 #include <stdio.h>
     6 #include <stdarg.h>
     7 
     8 #ifndef UNDEBUG_FILE
     9 #define DEBUG_FLAG 1
    10 #else
    11 #define DEBUG_FLAG 0
    12 #endif
    13 
    14 #if (DEBUG_FLAG == 1)
    15 
    16 static unsigned int __sdebug_time = 0;
    17 #define  __debug_Msg_Size 1024
    18 static char __pdebug_Msg[__debug_Msg_Size];
    19 //注意下面的__attribute__不是C标准。。。。
    20 static void __debug_info(const char *prefix,const char *fmt, ...) __attribute__((format (printf, 2, 3)));
    21 #define __NEXT_DBG_TIME() do{sdebug_time++;}while(0)
    22 #define __PRINT_POS() do {fprintf(stderr,"%s(%d){%s}",__FILE__,__LINE__,__func__);}while(0)
    23 #define __FUNC_LOG() do{__PRINT_POS();fprintf(stderr,": t = %d ",__sdebug_time++);} while(0)
    24 #define __FUNC_LOGn() do{__FUNC_LOG();fprintf(stderr,"
    ");} while(0)
    25 #define __PRINT_POS_exp(exp) do{__PRINT_POS();fprintf(stderr,"| (%s):",#exp);}while(0)
    26 #define __PRINT_POS_P_exp(prefix,exp) do{__PRINT_POS();fprintf(stderr,"|<%s> (%s):",prefix,#exp);}while(0)
    27 #define __PRINT_POS_expn(exp)  do{__PRINT_POS_exp(exp);fprintf(stderr,"
    ");}while(0)
    28 #define __PRINT_POS_P_expn(prefix,exp) do{__PRINT_POS_P_exp(prefix,exp);fprintf(stderr,"
    ");}while(0)
    29 #define __ASSERT(exp) do{if (exp){}else{__PRINT_POS_P_expn("ASSERT ERROR",exp);}}while (0)
    30 #define __ASSERT_EXIT(exp) do{if (exp){}else{__PRINT_POS_P_expn("ASSERT ERROR",exp);exit(1);}}while (0)
    31 
    32 #define __debug_info_LOG(exp,PREFIX,fmt,...) do{if (exp){__PRINT_POS_P_exp(PREFIX,exp);__debug_info(PREFIX,fmt,__VA_ARGS__);}}while (0)
    33 
    34 #define __ASSERT_LOG(exp,fmt,...) __debug_info_LOG(exp,"ASSERT!",fmt,__VA_ARGS__)
    35 #define __ERROR_LOG(exp,fmt,...) __debug_info_LOG(exp,"ERROR!",fmt,__VA_ARGS__)
    36 define __BEFORE_LOG(N,fmt,...)  do {__debug_info_LOG((N) < __sdebug_time,"BEFORE!",fmt,__VA_ARGS__);__NEXT_DBG_TIME()}while(0) 
    37 #define __AFTER_LOG(N,fmt,...) do {__debug_info_LOG((N) >= __sdebug_time,"AFTER!",fmt,__VA_ARGS__); __NEXT_DBG_TIME();}while(0) 
    38 static void __debug_info(const char *prefix,const char *fmt, ...) {
    39     va_list params;    
    40     va_start(params, fmt);
    41     __ASSERT_EXIT((__pdebug_Msg) && (__pdebug_Msg_Size ));
    42     vsnprintf(__pdebug_Msg, __pdebug_Msg_Size, fmt, params);
    43     if (prefix){
    44         fprintf(stderr, " %s %s
    ", prefix, __pdebug_Msg);
    45     }else{
    46         fprintf(stderr, " %s
    ", __pdebug_Msg);
    47     }
    48     va_end(params);
    49 }
    50 #else
    51 #define __NOP do{}while(0)
    52 #define __NEXT_DEBUG_TIME() __NOP
    53 #define __FUNC_LOGn() __NOP
    54 #define __FUNC_LOG() __NOP
    55 #define __PRINT_POS_Sn(exp)  __NOP
    56 #define __PRINT_POS_S(exp) __NOP
    57 #define __ASSERT(exp) __NOP
    58 #define __ASSERT_EXIT(exp) __NOP
    59 #define __debug_info_LOG(exp,PREFIX,fmt,...) __NOP
    60 #define __ASSERT_LOG(exp,fmt,...) __NOP
    61 #define __ERROR_LOG(exp,fmt,...) __NOP
    62 #define __BEFORE_LOG(N,fmt,...) __NOP 
    63 #define __AFTER_LOG(N,fmt,...) __NOP  
    64 
    65 #endif
    66 #endif

    上面

     1 UNDEBUG_FILE 

    是如下用法,如果你觉得加了一对debug信息太乱,那么整体C文件(模块)暂时没错可以如下

    1 ...
    2 #define UNDEBUG_FILE
    3 #include "debug.h"
    1 __FUNC_LOGn();

    可以写在每个函数的入口。这对跟踪函数之间的调用很有帮助(注意不是LOG,LOG打印这些就是没事找事了)

    1 __PRINT_POS_Sn

    主要是,例如指针跑飞,可以在各个地方加插该内容,以判断是否经过该地方。其和

    1 __FUNC_LOGn();

    输出是一样,但前者不影响sdebug_time。可以给出文件路径,行号,函数名和位置。一些输出情况如下:

    1 src/graph.c(90){create_graph_abs_by_ID}: t = 0
    2 src/graph_abstract.c(40){refresh_graph_abs}: t = 0
    3 src/graph_abstract.c(41){refresh_graph_abs}: t = 1
    4 src/graph_abstract.c(41){refresh_graph_abs}|<ASSERT!> (1): N = 82
    5 src/graph_abstract.c(42){refresh_graph_abs}: t = 2
    6 src/graph.c(91){create_graph_abs_by_ID}: t = 1 

    上面的内容就是上述头文件被#include到graph.c ,graph_abstract.c中,对应调用

    1 __FUNC_LOGn();
    2 以及 
    3  __ASSERT_LOG(1,"N = %d",N);

    的结果。需要注意,__ASSERT_LOG,我和传统的__ASSERT是反过来的。此处表示,断言成立下,才LOG信息到stderr中。

    1 src/graph_abstract.c(42){refresh_graph_abs}: t = 2

    实际上表示对 

    1 __sdebug_time

    第3次累加的位置。其实比如该文件对应累加

    1 __sdebug_time

    运行了6000次后才出现某个情况出错,则可以使用

    1 __AFTER_LOG

    __BEFORE_LOG则是反过来。

    1 __ASSERT_LOG
     

    这相对F5,F9,F10,仅针对静态代码,进行断点要方便的多。当然你要额外增加一堆if判断,再加F9,我也没意见。哈。

    http://www.oschina.net/question/249672_59411

    vs不支持 __func__ 用 __FUNCTION__ 代替
  • 相关阅读:
    C#之流程控制
    UML画图总结以及浅谈UNL九种图
    UML视频总结
    英语总结
    UML coming
    那天我把“小四”拆了
    first 关于文档(总结)
    机房收费需求分析文档
    梦开始的地方
    WebRTC 开发实践:为什么你需要 SFU 服务器
  • 原文地址:https://www.cnblogs.com/youngt/p/3680990.html
Copyright © 2011-2022 走看看