我无法找到以下问题的答案,而且我遇到了一些与功能相关的问题。
我的主要编程是用C#完成的,在学习的时候从未真正学过C ++,但在我目前的工作中,我还要做一些C ++编程。
大多数C ++编程都是由一名前员工完成的,他为日志记录创建了一个函数。
偶尔这个函数会导致错误(访问冲突) - 这不会向用户显示,但我在通过调试器运行代码时看到它。
当错误发生时,它指向这行代码:
vfprintf( LogFile, fmt, va );
然后我仔细研究了之前和之后的代码,并将上面的代码置于上下文中:
void FileLog( char *fmt, ... )
{
va_list va;
struct time t;
struct date d;
long clk;
static int ReEntrant = 0;
if( FileLogEnabled == false )
return;
ReEntrant++;
if( ReEntrant > 1 )
return;
if( LogFile == NULL )
LogFile = fopen( LogFileName, "a+" );
if( LogFile != NULL )
{
gettime( &t );
getdate( &d );
fprintf( LogFile, "\n%d-%02d-%02d %2d:%02d:%02d.%02d0> ", d.da_year, d.da_mon, d.da_day, t.ti_hour, t.ti_min, t.ti_sec, t.ti_hund );
va_start( va, fmt );
vfprintf( LogFile, fmt, va );
va_end( va );
fflush( LogFile );
...
}
ReEntrant = 0;
}
其实我不明白为什么需要它(如果是的话?)同时调用fprintf然后调用vfprintf?我认为第一个fprintf调用会将格式化的字符串写入流(文件),这就足够了吗?
一点点解释或一些信息将非常感激:)
编辑:在来自nos的评论之后 - 我追踪了对今天经常导致此错误的函数的特定调用。
FileLog( "TimerRestore[%d], Name=%s", Package.CurGame->Timers[ Index ].Name.c_str() );
我确实认为这可能会造成一些麻烦,因为“TimerRestore [%d],Name =%s”后面应该跟一个小数和字符串arguemtn,但是只给出一个字符串参数。我需要做一些测试,但我确信写这段代码的作者想要写:
FileLog( "TimerRestore[%d], Name=%s", Index, Package.CurGame->Timers[ Index ].Name.c_str() );
但是我仍然不明白为什么函数调用似乎并不总是导致错误。或者可能是因为FileLog函数中的“ReEntrant”变量在没有失败时会阻塞它?
非常感谢所有反馈和信息。
答案 0 :(得分:8)
vprintf()
(和朋友)允许使用va_list
作为参数,这在函数具有可变数量的参数时很有用:
void log(FILE *file, const char* format, ... )
{
va_list args;
va_start (args, format);
fprintf(file, "%s: ", getTimestamp());
vfprintf (file, format, args);
va_end (args);
}
在您的应用程序中,您可以使用可变数量的参数调用此函数:
log(file, "i=%d\n", i); // 3 arguments
log(file, "x=%d, y=%d\n", x, y); // 4 arguments
我不知道为什么你的功能会导致错误。您的代码段未提供足够的详细信息。提供的函数参数的类型数量可能是的原因。
答案 1 :(得分:2)
首先,在C ++中使用fprintf()
和(特别是)vfprintf()
邪恶。
要点:fprintf()
是一个可变函数,它接受任意数量的参数。在内部,可变函数是通过使用va_list
,va_start()
和va_end()
“解包”可变参数来实现的。
vfprintf()
的函数时,使用 fprintf()
va_list
实例)。 vfprintf()
不可变参数;它接受存储参数的va_list
。
您尚未发布调用fprintf()
和vfprintf()
的函数声明,但我们可以假设它是可变参数。它首先使用fprintf()
将一些数据打印到LogFile
,然后使用vfprintf()
在那里打印自己的可变参数。
答案 2 :(得分:0)
vfprintf
允许您拥有变量参数列表,这意味着您可以在运行时动态创建参数列表。
答案 3 :(得分:0)
这对于日志记录来说非常常见。您想要制作类似于:
的printf样式的日志消息Log("The value of x is now %d", x);
但这需要变量参数。所以你需要vfprintf
。使用fprintf
的原因是因为它想要写一个日期/时间戳,你不能将这些额外的东西添加到传递给vfprintf
的现有格式中。
另一种方法是使用字符串版本vsprintf
,并创建一个大字符串,然后将其写入文件。但是这更容易出错(比如缓冲区溢出)。