我在程序中获得以下功能:
void log(char* arg1, ...)
{
time_t t;
struct tm *tm;
va_list args;
char *fmt;
char curtime[TIME_STR_SIZE];
FILE *fd;
va_start(args, arg1); // linux stdarg va_start req 2 args - va_lilst, parm_n
fmt = va_arg(args, char*);
if (lfd == NULL)
fd = stderr;
else
fd = lfd;
(void) time(&t);
tm = localtime(&t);
sprintf(curtime, "%02d.%02d.%d, %02d:%02d:%02d", tm->tm_mday, tm->tm_mon+1, tm->tm_year+1900, tm->tm_hour, tm->tm_min, tm->tm_sec);
fprintf(fd, "%s: ", curtime);
vfprintf(fd, arg1, args);
fprintf(fd, "\n");
fflush(fd);
va_end(args);
}
显然它需要一个输入参数列表并将它们写入文件。
但运行这部分代码会引发一个分段错误,我已经回溯到vfprintf:
(gdb) backtrace
#0 0x00007ffff4799db2 in __strlen_sse2 () from /lib64/libc.so.6
#1 0x00007ffff476220d in vfprintf () from /lib64/libc.so.6
#2 0x0000000000401b03 in log (arg1=0x40529d "%s gestartet: PID = %d") at logging.c:73
#3 0x00000000004045d4 in main (argc=10, argv=0x7fffffffdc98) at abgleich.c:589
运行gdb并打印参数时很好:
(gdb) print fd
$9 = (FILE *) 0x607010
(gdb) print fmt
$10 = 0x7fffffffe1a7 "/srv/workspace/abgleich/abgleich"
(gdb) print args
$11 = {{gp_offset = 16, fp_offset = 48, overflow_arg_area = 0x7fffffffda10, reg_save_area = 0x7fffffffd950}}
我很好奇为什么会抛出分段错误,因为它在这种情况下看起来是一个明确定义的输入。
该功能的调用部分如下:
log("%s gestartet: PID = %d", argv[0], getpid());
编辑:
我已按以下方式使用va_copy重写:
va_start(args, arg1); // linux stdarg va_start req 2 args - va_lilst, parm_n
va_copy(c_args, args);
if (lfd == NULL)
fd = stderr;
else
fd = lfd;
(void) time(&t);
tm = localtime(&t);
/* strftime(curtime, TIME_STR_SIZE, "%d.%m.%y, %H:%M:%S\0", time_ptr); */
sprintf(curtime, "%02d.%02d.%d, %02d:%02d:%02d", tm->tm_mday, tm->tm_mon+1, tm->tm_year+1900, tm->tm_hour, tm->tm_min, tm->tm_sec);
fprintf(fd, "%s: ", curtime);
vfprintf(fd, arg1, c_args);
fprintf(fd, "\n");
fflush(fd);
va_end(args);
答案 0 :(得分:3)
使用va_arg()
"功能"在从va_list
获得的va_start()
上,va_list
被修改,因此当传递给另一个函数时,它与您在开始时的不同。您可以将va_list
视为指针,使用va_arg()
就像增量运算符(++)。你可以这样称呼你的函数:
log("%s gestartet: PID = %d", argv[0], getpid());
但是vfprint很可能会这样看:
vfprintf(fd, "%s gestartet: PID = %d", /* argv[0], <-- REMOVED */ getpid());