我正在进行一些调试,希望将标准错误消息重定向到一个文件;因此,它可以在调试日志文件中查看。我确实需要从C代码中完成,而不是通过UNIXshell重定向。
我需要调试一些这样的模块。我有一套调试工具,可以写入strerr(控制台(。它很容易包含在源代码中,并提供一组舒适的宏和函数,用于调试源代码。
以下是头文件中的代码。
#include <stdio.h>
#define LOGWRAPPER(tag, fmt, args...)
fprintf(stderr, "%s: " fmt "n", tag, ##args)
#define LOG_DEBUG(...) LOGWRAPPER(__VA_ARGS__)
...
...
#define LOG_DEBUG(tag, fmt, args...)
do {
(true) ? ALOG(LOG_DEBUG, tag, fmt, ##args)
: fprintf(stderr, "%s" fmt, tag, ##args);
} while (0)
....
最终,所有打印都将返回到这里,即头文件。所以我想我必须对做一些改变
#define LOGWRAPPER(tag, fmt, args...)
fprintf(stderr, "%s: " fmt "n", tag, ##args)
知道吗?或者我应该创建一个文件路径并插入fprintf吗?
在C代码中重定向stderr
的一种典型方法是使用dup2()
(本质上(将文件描述符映射到一个新文件。例如:
int f=打开("mylog.txt",O_CREAT|O_RDWR|O_APPEND,0644(;dup2(f,STDERR_FILENO(;
还有其他方法——例如,可以在stderr
上使用freopen()
。
但是。。。
如果你使用你定义的宏进行所有日志记录,为什么不简单地定义宏来做一些完全不同的事情呢?也就是说,定义LOG_DEBUG
来调用您提供的函数,而不是定义fprintf()
?
我相信对此还有其他意见,但我不喜欢使用stderr
进行常规日志记录。我只想让stderr
得到严重的、破坏程序的错误消息。有可能(也许(您的代码并不是唯一可以写入stderr
的代码——库也可以这样做。收集它们的输出并将其发送到常规调试日志可能是合适的,但也可能不是。我总是使用专门用于此目的的函数进行常规日志记录。
我确实需要从C代码中完成,而不是通过UNIXshell重定向。
了解shell如何实现重定向将使您对如何在自己的程序中实现重定向有必要的了解。
POSIX定义了在每个进程开始时可用的三个标准文件描述符:0=stdin,1=stdout,2=stderr
C标准库还定义了通过全局可用符号暴露的三个FILE*
流,它们分别命名为stdin
、stdout
和stderr
,并直接对应于数字文件描述符;POSIX标准定义了在CCD_ 14流上操作的称为CCD_。
归根结底,一切都归结为文件描述符。
尽管可以将现有流freopen
发送到新的目的地,但这通常会产生一个新的、不同的文件描述符。虽然您重新生成的FILE*
流(可能通过像stderr
这样的全局符号(将转到该新位置,但它不会影响程序中绕过C标准库函数的部分因此,建议的方法是替换文件描述符本身,这就是系统调用dup2
所做的。
使用dup2
,您可以获取一个现有的文件描述符,并在另一个现有文件描述符上重复覆盖它。因此,如果您打开一个日志文件,并在文件描述符2(=stderr(上复制它,它的输出将重定向到那里。
这就是shell重定向的方式,您也可以在程序中使用它:
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
/* replace fd=2, i.e. stderr, with a file of our choosing: */
int fd_logfile = open("logfile.txt", O_RDWR | O_CREAT | O_APPEND, 0644);
if( 0 <= fd_logfile ){
dup2(fd_logfile, 2);
close(fd_logfile);
}
/* ... */
fprintf(stderr, "This should go to logfile.txtn");
}