C++ C+中的fprintf和vfprintf有什么区别+;?

C++ C+中的fprintf和vfprintf有什么区别+;?,c++,c,access-violation,printf,C++,C,Access Violation,Printf,我还没有找到以下问题的答案,我遇到了一些与函数相关的问题 我的主要编程是在C语言中完成的,在学习的时候从来没有真正学会过C++,但是在我现在的工作中,我还必须做一些C++编程。 大多数C++编程都是由一个前雇员完成的,他为日志记录做了一个功能。 偶尔,这个函数会导致一个错误(访问冲突)-这不会显示给用户,但我在通过调试器运行代码时看到它 当错误发生时,它指向以下代码行: vfprintf( LogFile, fmt, va ); 然后,我仔细查看了前后的代码,并将上面的内容放到上下文中,代码是

我还没有找到以下问题的答案,我遇到了一些与函数相关的问题

我的主要编程是在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函数中的“可重入”变量在未失败时阻塞它的原因

非常感谢您提供的所有反馈和信息。

vprintf()
(和朋友)允许用作参数,这在函数具有可变数量的参数时非常有用:

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
在应用程序中,您可以使用可变数量的参数调用此函数:

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

我不知道为什么您的函数会导致错误。您的代码片段没有提供足够的详细信息。提供的函数参数类型的数量可能是原因。

vfprintf
允许您拥有变量参数列表,这意味着您可以在运行时动态创建参数列表。

这对于日志记录非常常见。您希望生成一条printf样式的日志消息,如:

Log("The value of x is now %d", x);
但这需要可变参数。所以您需要
vfprintf
。之所以使用
fprintf
,也是因为它想写一个日期/时间戳,而您不能将额外的内容添加到传递给
vfprintf
的现有格式中


另一种方法是使用字符串版本
vsprintf
,生成一个大字符串,然后将其写入文件。但这更容易出错(如缓冲区溢出)。

第一次,使用<代码> fPrtuff()/Cuff>和(特别是<代码> VfPrimff())/<代码> C++ > <强>邪恶> < /强>

说到这里:
fprintf()
是一个可变函数,它接受任意数量的参数。在内部,可变函数通过使用
va_list
va_start()
va_end()
来“解包”可变参数来实现

vfprintf()
用于在解压自己的可变参数后,想要从自己的可变函数访问
fprintf()
的功能时(即,您可以访问
va_列表
实例)
vfprintf()
可变的;它接受存储参数的
va_列表


您还没有发布调用函数的声明
fprintf()
vfprintf()
,但我们可以假设它是可变的。首先使用<代码> fPrtuff()/C++ >将一些数据打印到日志文件< /C>中,然后使用<代码> vfPrimff()/Cuff>打印其自己的变量参数。它们是不同的语言,有不同的习惯用法。这个日志函数是从多个线程调用的吗?
gettime
getdate
函数中是否涉及任何静态信息?如果查看代码,第一个fprintf()调用仅将日期/时间写入日志文件。vfprintf()调用打印实际的日志消息。如果调用者为日志消息提供了自己的格式字符串,则不能组合这些字符串。然而,实际的错误并不在调试器停止的那一行,这是因为有人使用无效参数调用此函数,您必须跟踪这些参数。实际上,不,看起来您对导致问题的原因是正确的。但我还是不完全明白为什么它不是每次都发生。当执行这一行时,我“经常”(有20-30%的时间)发生:FileLog(“TimerRestore[%d],Name=%s”,Package.CurGame->Timers[Index].Name.c_str());。事实上,我认为第一个字符串应该有2个参数,而它只有1个参数。但为什么它不总是失败呢?@Knirkegaard说,这条线路有一个明显的错误,这将导致不可预测的行为
TimerRestore[%d],Name=%s“
包含两个格式说明符,“%d”和“%s”,但您只提供了一个参数,
Package.CurGame->Timers[Index].Name.c_str()
您能提供一个链接或其他证据证明它是邪恶的吗?@paddy我手头没有链接,但我会解释自己:
fprintf()
是类型不安全的。如果参数和格式说明符不匹配,则这是一个运行时错误,如果使用iostreams,这将是编译时错误。使用
vfprintf()
意味着编写一个(C风格)变量函数,这同样是非常不安全的类型。将非平凡类传递到此类函数中是“通过实现定义的语义(引用标准)有条件地支持。当然,但不具备类型安全性并不意味着它是邪恶的……它只是意味着您必须小心。使用