【发布时间】:2013-01-16 12:28:06
【问题描述】:
我无法找到以下问题的答案,并且遇到了一些与功能相关的问题。
我的主要编程是用 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”变量在它没有失败时阻塞它的原因?
非常感谢您提供的所有反馈和信息。
【问题讨论】:
-
请不要将 C++ 和 C 放在一个人为的术语“C/C++”中。它们是具有不同习语的不同语言。
-
这个日志记录函数是否被多个线程调用?
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"包含 2 个格式说明符“%d”和“%s”,但您只提供一个参数Package.CurGame->Timers[ Index ].Name.c_str()
标签: c++ c access-violation printf