如何检测正确的函数调用对

时间:2010-08-13 20:57:55

标签: c++ c

我正在寻找一种能够以嵌套方式检测有序函数调用对的工具,如下所示:

f()   // depth 0
   f()  //depth 1
   g()
g()

在每个呼叫深度f(),必须有g()调用形成函数呼叫对。这在关键部分进入和退出时尤其重要。

4 个答案:

答案 0 :(得分:11)

在C ++中,一个选项是在类的构造函数和析构函数中包含对f()g()的调用,并且只通过实例化该类的实例来调用这些函数。例如,

struct FAndGCaller
{
    FAndGCaller() { f(); }
    ~FAndGCaller() { g(); }
};

然后可以在任何范围块中使用它,如下所示:

{
    FAndGCaller call_f_then_later_g; // calls f()

} // calls g()

显然,在实际代码中,您需要更恰当地命名,并且通常只需要在构造函数和析构函数体中包含f()g()的内容,而不是单独的职能。

范围界限资源管理(SBRM,或更常见的资源获取是初始化,RAII)的这种习惯用法非常普遍。

答案 1 :(得分:2)

您可能会滥用for - 循环。

#define SAVETHEDAY for (bool seen = ((void)f(), true); seen; seen = ((void)g(), false))

逗号运算符始终让您的函数f在依赖语句之前执行,之后执行g。 E.g

SAVETHEDAY {

    SAVETHEDAY {

    }
}

优点:

  • 使嵌套级别清晰。
  • 适用于C ++和C99。
  • for - 循环将是 任何体面的优化 编译器。

缺点:

  • 你可能会有惊喜 breakreturncontinue 在块内部,因此在这种情况下可能不会调用g
  • 对于C ++,这对a不安全 在throw内,再次g可能不会被称为
  • 许多人都不赞同,因为某种语言可以扩展语言。
  • 许多人会不满意 特别是对于C ++,一般来说 这些隐藏代码的宏是 被认为是邪恶的

continue的问题可以通过更巧妙地处理来修复。 通过使用伪类型for - 在构造函数和析构函数中只有fg的变量,可以在C ++中规避前两个缺点。

答案 2 :(得分:0)

扫描代码(这是困难的部分),每次看到f()的调用时,都会增加一个计数器。每次看到g()的调用时,都会递减计数器。最后,计数器应该回零。如果它变为负数,那么这也是一个问题(您呼叫g()之前没有匹配调用f())。

准确地扫描代码是困难的部分 - 使用C和(特别是)C ++,编写代码来理解源代码非常困难。另外,我不知道这个特定工作的现有工具。你可以毫无疑问地得到clang(举一个例子)去做,虽然它比完全靠你自己做的容易得多,但它仍然不会是微不足道的。

答案 3 :(得分:0)

用于语义搜索和修补C代码的Coccinelle工具专为此类任务而设计(另请参阅工具上的this LWN article)。