打印调试

系统提供了vprintf系列格式化字符串的函数,用于编程人员封装自己的I/O函数。
 
FILE *logfile;
 
int WriteLog(const char * format, ...)
 
{
 
va_list arg_ptr;
 
va_start(arg_ptr, format);
 
int nWrittenBytes = vfprintf(logfile, format, arg_ptr);
 
va_end(arg_ptr);
 
return nWrittenBytes;
 
}
 
va的宏定义在stdarg.h中,它们有:va_list,va_start(),va_arg(),va_end()。
 
va_list型变量:
#ifdef _M_ALPHA
typedef struct {
char *a0; /* pointer to first homed integer argument */
int offset; /* byte offset of next parameter */
} va_list;
#else
typedef char * va_list;
#endif

 简单地说,va函数的实现就是对参数指针的使用和控制。
 
typedef char *  va_list;  // x86平台下va_list的定义 。
 


对于可选参数部分,先将指针指向第一个可选参数,然后依次后移指针,
 
根据与结束标志的比较来判断是否已经获得全部参数。
 
因此,va函数中结束标志必须事先约定好,否则,指针会指向无效的内存地址,导致出错。

调试常用的 __FILE__, __FUNCTION__, __LINE__
 下面是一个可供调试用的头文件
 #ifndef _GOLD_DEBUG_H
 #define _GOLD_DEBUG_H
 
 
 
#ifdef __cplusplus
 #if __cplusplus
 extern "C"{
 #endif
 #endif /* __cplusplus */
 

#ifdef GI_DEBUG
 
#define GI_DEBUG_POINT()   printf("\n\n[File:%s Line:%d] Fun:%s\n\n", __FILE__, __LINE__, __FUNCTION__)
 #define dbg_printf(arg...)   printf(arg);
 
#define GI_ASSERT(expr)                                     \
     do{                                                     \
         if (!(expr)) { \
             printf("\nASSERT failed at:\n  >File name: %s\n  >Function : %s\n  >Line No. : %d\n  >Condition: %s\n", \
                     __FILE__,__FUNCTION__, __LINE__, #expr);\
         } \
     }while(0);
 
/*调试宏, 用于暂停*/
 #define GI_DEBUG_PAUSE()           \
  do               \
  {               \
   GI_DEBUG_POINT();          \
   printf("pause for debug, press 'q' to exit!\n");  \
   char c;             \
   while( ( c = getchar() ) )        \
    {             \
     if('q' == c)         \
      {           \
       getchar();        \
       break;         \
      }           \
    }             \
  }while(0);
 #define GI_DEBUG_PAUSE_ARG(arg...)          \
   do               \
   {               \
    printf(arg);           \
    GI_DEBUG_PAUSE()          \
   }while(0);
 

#define GI_DEBUG_ASSERT(expression)      \
 if(!(expression))                        \
 {                                  \
     printf("[ASSERT],%s,%s:%d\n", __FILE__,  __FUNCTION__, __LINE__);\
     exit(-1);             \
 }
 #else
 #define GI_ASSERT(expr)
 #define GI_DEBUG_PAUSE()
 #define GI_DEBUG_PAUSE_ARG(arg...)
 #define GI_DEBUG_POINT()
 #define dbg_printf(arg...)
 #define GI_DEBUG_ASSERT(expression)
 
#endif
 
#ifdef __cplusplus
 #if __cplusplus
 }
 #endif
 #endif /* __cplusplus */
 

#endif

VC6 不支持 __FUNCTION__ 所以可以写下面函数:
//用来记录当前行和当前函数//也可说是记录 堆栈
 void log_stack(const char *file, int line, const char * function);
//当然还要对 __FUNCTION__ 宏作点修饰,因为这个宏只是在函数里面才起作用
 //据说 VC6 也是不支持 __FUNCTION__ 的
 #ifndef __FUNCTION__
     #define __FUNCTION__ "Global"
 #endif
 
#define DEBUG_NEW_HOOK
 
#ifdef DEBUG_NEW_HOOK
   //就是先写跟踪信息再实际调用函数
   #define  debug_new_check_point(a)  log_stack(__FILE__, __LINE__, __FUNCTION__); debug_new_check(a, false)
   #define  debug_new_check_free(a)  log_stack(__FILE__, __LINE__, __FUNCTION__); debug_new_check(a, true)
 #else
 
#endif
作为一个C++程序员,可能经常遇到 __TIME__、__FILE__、__DATE__ 这样的宏,它们会在编译时,分别转换为包含编译时间、处理的转换单元名称及当前时间的字符串
通常,在调试中最让人心烦的阶段,是不断地检查是否已调用了特定的函数。对此问题的解决方法,一般是添加一个cout或printf()——如果你使用C语言,如下所示:
 void myfunc()
 {
 cout<<"myfunc()"<<endl;
 //其他代码
 }
  通常在一个典型的工程中,会包含有数千个函数,要在每个函数中都加入一条这样的输出语句,无疑难过上“蜀山”啊,因此,需要有一种机制,可以自动地完成这项操作。
在最新的ISO C标准中,如大家所知的C99,加入了另一个有用的、类似宏的表达式__func__,其会报告未修饰过的(也就是未裁剪过的)、正在被访问的函数名。请注意,__func__不是一个宏,

因为预处理器对此函数一无所知;相反,它是作为一个隐式声明的常量字符数组实现的:
 static const char __func__[] = "function-name";
 

  在function-name处,为实际的函数名。为激活此特性,某些编译器需要使用特定的编译标志,
有了它,我们可免去大多数通过手工修改,来显示函数名的苦差事,以上的例子可如下所示进行重写:
 void myfunc()
 {
 cout<<"__FUNCTION__"<<endl; //打印出myfunc 函数名
 }
 在Visual Studio 2005中,默认情况下,此特性是激活的,但不能与/EP和/P编译选项同时使用。请注意在IDE环境中,不能识别__func__ ,而要用__FUNCTION__ 代替。
GCC 3.0及更高的版本同时支持 __func__ 和__FUNCTION__ 。

你可能感兴趣的:(打印调试)