temp2

?用到第三方库使用printf打印调试信息的时候往往需要重定向日志到文件, 但如果没有源码或修改点较多时就比较麻烦. 这里提供两个重定位方法:
?1. 修改值为1的文件描述符
?默认printf打印指向标准输出stdout(fd=1), 最终指向终端. 因此可以关闭值为1的文件描述符再打开另一文件, 之后printf打印就被写入该文件中. 注意这种方法必须保证关闭fd与打开文件之间不会有其它文件操作(内核分配fd是顺序分配的, 如有第三个文件打开则第三个文件的fd被设为1), 且fork进程会保留对应的fd, 即新进程也会操作同一文件, 需要做好互斥(可以通过关闭子进程fd来解决这个问题).
?2. 修改printf实现
?定义同名同类型的printf并修改其实现. 这里要注意一点, 默认打印不带参数的字符串时gcc会将printf优化为puts, 解决办法有两个: 一是同样重定义puts, 二是编译时添加-fno-builtin-printf.
?
?#include <string.h>
?#include <stdlib.h>
?#include <stdio.h>
?#include <fcntl.h>
?#include <stdarg.h>
?
?#define REDIRECT
?#undef REDIRECT
?
?#ifdef REDIRECT
?int fd = -1;
?#else
?FILE *fp = NULL;
?int printf(const char *fmt, ...)
?{
? ? ? ? va_list args;
? ? ? ? int ret = 0;
?
? ? ? ? va_start(args, fmt);
? ? ? ? ret = vfprintf(fp, fmt, args);
? ? ? ? va_end(args);
? ? ? ? fflush(fp);
? ? ? ? return ret;
?}
?
?/*
?int puts(const char *s)
?{
? ? ? ? //add \n here to avoid buffering
? ? ? ? return printf("%s\n", s);
?}
?*/
?#endif
?
?int main()
?{
?#ifdef REDIRECT
? ? ? ? close(1);
? ? ? ?
? ? ? ? fd = open("./out", O_RDWR | O_CREAT, 0755);
? ? ? ? if (1 != fd)
? ? ? ? {
? ? ? ? ? ? ? ? fprintf(stderr, "open file fail with %d\n", fd);
? ? ? ? ? ? ? ? return -1;
? ? ? ? }
?
? ? ? ? printf("this line shall written into file!\n");
? ? ? ? //flush cache, man stdout for detail
? ? ? ? fsync(fd);
?#else
? ? ? ? fp = fopen("./out", "w+");
? ? ? ? if (NULL == fp)
? ? ? ? {
? ? ? ? ? ? ? ? fprintf(stderr, "open file fail\n");
? ? ? ? ? ? ? ? return -1;
? ? ? ? }
?
? ? ? ? const char cmd[] = "this line shall written into file!\n";
? ? ? ? printf("this line shall written into file!\n");
? ? ? ? printf("this line shall written into file! more args %p\n", fp);
?#endif
?
? ? ? ? return 0;
?}
?
?
?

猜你喜欢

转载自www.cnblogs.com/Five100Miles/p/9096124.html