2011-12-30 56 views
4

我想知道为什么它倾向于重定向调试语句到标准错误就像是在这里完成:为什么以及如何重定向调试语句?

#ifdef DEBUG_TEST 
    #define DEBUG_TEST 1 
    #else 
    #define DEBUG_TEST 0 
    #endif 

    #define DEBUG_PRINT(fmt, ...) \ 
      do { if (DEBUG_TEST) fprintf(stderr, fmt, ##__VA_ARGS__); } while (0) 

另外:我们怎样才能重定向这些调试语句发送到一个单独的日志文件,在该文件的时间戳?我想在我的代码中使用宏来完成此操作。

平台:Linux,gcc编译

回答

2

我可以给你的,你为什么会做这样的两个例子:你可以再标准输出轻松重定向到一个文件,同时保持标准错误在你的终端(这似乎是正是你想要做的第二个问题)。您的工具可能会突出显示发送到stderr的邮件,以便马上发现。

您可以使用命令行版本重定向stderr,如同样的建议。若要获取文件名时间戳,你可以做这样的事情,当你运行你的程序:

./program 2>"logfile-`date`.txt" 

如果你想这样做的节目本身,一个办法就是使用的fopen打开另一个文件,写信给那个。这里是一个完全工作的例子,你可以玩:使用标准错误在标准输出的

#include <time.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <stdbool.h> 

#define DEBUG_TEST true 

FILE *debug_file; 

#define DEBUG_PRINT(fmt, ...) \ 
     do { if (DEBUG_TEST) fprintf(debug_file, fmt, ##__VA_ARGS__); } while (false); 



int main() 
{ 
     time_t timestamp = time(NULL); 
     char * s = malloc(snprintf(NULL, 0, "debug-%d.txt", timestamp)); 
     sprintf(s, "debug-%d.txt", timestamp); 

     debug_file=fopen(s, "w"); 

     DEBUG_PRINT("YEAH\n"); 

     fclose(debug_file); 

     return EXIT_SUCCESS; 
} 
+0

+1。很好的解释。 – dicaprio 2011-12-30 07:39:00

3

好处是,如果你是将输出重定向到一个文件或串流播放(使用管道)到另一个进程,调试信息不要妨碍。

如果你想标准错误重定向到UNIX上的文件,你可以像这样运行程序:

./program 2>logfile 
+0

谢谢...这意味着我们可以安全地重定向到标准输出......是否正确。 – john 2011-12-30 06:36:40

+0

可以告诉我如何在我的代码中定义一个“像宏一样的函数”来执行此操作(意味着将日志重定向到日志文件)... – john 2011-12-30 06:40:39

+0

记录到文件将不仅仅是一个宏。您可以使用像google-glog这样的日志库,或者将stderr或stdout重定向到程序外的文件。 – thesamet 2011-12-30 06:55:01

1

其中一个原因你报告调试信息stderr,而不是stdout因为stdout可能关闭发送管道和诊断将与实际数据一起进行,混淆了管道的后续阶段。

如果您可能想要重定向输出或添加时间戳(或PID或任何其他信息),则请勿直接使用fprintf()。调用你自己设计的功能,以你想要的方式处理你想要的信息。

因此,您的宏可能是:

extern void dbg_print(const char *fmt, ...); 

#define DEBUG_PRINT(fmt, ...) \ 
     do { if (DEBUG_TEST) dbg_print(fmt, __VA_ARGS__); } while (0) 

或者:

extern void dbg_print(const char *func, const char *file, int line, const char *fmt, ...); 

#define DEBUG_PRINT(fmt, ...) \ 
     do { if (DEBUG_TEST) dbg_print(__func__, __FILE__, __LINE__, fmt, __VA_ARGS__); } while (0) 

这包括信息

例如,我有函数名,文件名和行号这是一个适度复杂的软件包。其中的核心内部例程的是:

/* err_stdio - report error via stdio */ 
static void err_stdio(FILE *fp, int flags, int errnum, const char *format, va_list args) 
{ 
    if ((flags & ERR_NOARG0) == 0) 
     fprintf(fp, "%s: ", arg0); 
    if (flags & ERR_STAMP) 
    { 
     char timbuf[32]; 
     fprintf(fp, "%s - ", err_time(timbuf, sizeof(timbuf))); 
    } 
    if (flags & ERR_PID) 
     fprintf(fp, "pid=%d: ", (int)getpid()); 
    vfprintf(fp, format, args); 
    if (flags & ERR_ERRNO) 
     fprintf(fp, "error (%d) %s\n", errnum, strerror(errnum)); 
} 

调试包装可以调用到用适当的标记,它们的功能,并生成希望的输出。系统的其他部分控制使用的文件流(stderr是默认设置,但有一个功能可将输出重定向到其他任何流),依此类推。

如果您通过在调试宏中直接使用fprintf()来限制自己,那么您可以使用fprintf()可以执行的操作或重新编译所有内容。

另请参阅我对'C#define macro for debug printing'的回答,以获取有关调试宏以及如何使用它们的更多信息(尽管看起来好像您已经在板上说了很多东西)。

1

原谅如果我错了,但似乎没有人提到缓冲。

默认情况下,stdout在大多数平台上是行缓冲的,而stderr是无缓冲的。基本上这意味着默认情况下,写入标准输出写入内存,并以块的形式写入文件或控制台,因为按字符输出的字符是slooooow。

如果你正在调试你不希望消息出现得太晚,那么你实际上意味着要打印它(甚至可能永远不会打印出来,如果你的程序崩溃或陷入无限循环(这可能会让你感到困惑)当你认为它的循环或崩溃在错误的地方时),并且你通常不介意速度问题,理论上它可能会因时序和同步错误而有所作为,但是在任何情况下很难捕获/调试它们。

TL; DR调试打印时,标准错误不是标准输出(其他人可能会建议记录到文件,而不是和或允许像启用/禁用打印文件,风格,阈值,ECT运行选项)

相关问题