2009-02-27 64 views
114

,和__FUNCTION__使用。假定你的C++编译器支持他们,是有什么特别的原因使用__FILE____LINE____FUNCTION__用于记录和调试的目的呢?__FILE__,__LINE__在C++

我主要关心的是给用户带来误导性数据 - 例如,报告不正确的行号或功能作为优化的结果 - 或因此导致性能下降。

基本上,我可以信任__FILE____LINE____FUNCTION__总是做正确的事?

+0

__LINE__应该做正确的事情。我广泛使用了它及其同类,包括__PRETTY_FUNCTION__。 ......但是......好吧,我现在正在查看__LINE__所在的代码。可能是因为它在try/catch异常处理的catch块中。 – 2012-10-11 05:08:24

+2

相关:[预定义宏的gcc参考](http://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html) – 2012-11-02 08:43:18

回答

140

__FUNCTION__是非标准的,__func__存在于C99/C++ 11中。其他人(__LINE____FILE__)都很好。

它会始终报告正确的文件和行(如果您选择使用__FUNCTION__/__func__)则会报告正确的文件和行。优化是一个非因素,因为它是编译时宏扩展;它会永不以任何方式影响性能。

+2

`__func__`在C++中是一个问题。 C99并没有对默认参数等进行说明,在`__func__`应该如何在C++中表现的情况下并不那么明显。 – wilhelmtell 2012-01-29 03:17:46

+3

@thr:虽然你说得很好。我清楚地知道`__func__`存在于c99中,而不是C++。无论如何,我认为在C++中合理实现`__func__`只会导致错误的名称。由于我不是编译器编写者,所以不是我的电话。 – 2012-04-05 03:13:16

+0

什么编译器根本不支持`__FUNCTION__`?除最近的gcc以外,哪些编译器将此视为变量,而不是宏? – basin 2013-01-18 09:11:21

7

就个人而言,我不愿意使用这些除了调试消息。我已经做到了,但我尽量不向客户或最终用户展示那种信息。我的客户不是工程师,有时不懂电脑。我可能会将这些信息记录到控制台,但是,正如我所说的,除了调试版本或内部工具外,不情愿。不过,我认为这取决于您拥有的客户群。

30

在极少数情况下,将__LINE__给出的行更改为其他内容可能会有用。我已经看到GNU配置对于某些测试来说,在原始源文件中没有出现的行之间插入一些voodoo之后,报告适当的行号。例如:

#line 100 

将使以下行以__LINE__ 100可以选择添加一个新的文件名

#line 100 "file.c" 

这只是很少有用。但如果需要的话,我不知道有什么替代方案。实际上,也可以使用一个宏,而不是该行,这必须导致上述两种形式中的任何一种。使用升压预处理库,您可以通过增加50当前行:

#line BOOST_PP_ADD(__LINE__, 50) 

我认为这是有益的提到它,因为你问起__LINE____FILE__使用。一个从来没有得到足够的惊喜出来的C++ :)

编辑: @Jonathan莱弗勒提供了一些更良好的使用情况的意见:

与#行梅辛是非常有用的预处理器是希望保持用户的C代码中报告的错误符合用户的源文件。 Yacc,Lex和ESQL/C预处理器(对我来说更多)。

22

供参考:g ++提供了非标准__PRETTY_FUNCTION__宏。直到现在我还不知道C99 __func__(感谢Evan!)。我认为当它可用于额外的类作用域时,我仍然更喜欢__PRETTY_FUNCTION__。

PS:

static string getScopedClassMethod(string thePrettyFunction) 
{ 
    size_t index = thePrettyFunction . find("("); 
    if (index == string::npos) 
    return thePrettyFunction; /* Degenerate case */ 

    thePrettyFunction . erase(index); 

    index = thePrettyFunction . rfind(" "); 
    if (index == string::npos) 
    return thePrettyFunction; /* Degenerate case */ 

    thePrettyFunction . erase(0, index + 1); 

    return thePrettyFunction; /* The scoped class name. */ 
} 
4

我用他们所有的时间。我唯一担心的是在日志文件中放弃IP。如果你的功能名称真的很好,你可能会更容易发现一个商业秘密。这有点像带调试符号,只是更难找到东西。在99.999%的情况下,没有什么不好的。