【问题标题】:Finding statement pattern in c++ file在 C++ 文件中查找语句模式
【发布时间】:2008-12-29 21:13:52
【问题描述】:

我有一个如下所示的宏:

#define coutError    if (VERBOSITY_SETTING >= VERBOSITY_ERROR)    ods()

其中 ods() 是一个行为类似于 cout 的类,而 VERBOSITY_SETTING 是一个全局变量。其中有一些用于不同的详细设置,它允许代码看起来像这样:

if (someErrorCondition)
{
    // ... do things relating to the error condition ...

    coutError << "Error condition occurred";
}

并且在这个框架中有设置详细程度等的功能。但是,当不使用大括号时,明显的模式会中断:

void LightSwitch::TurnOn()
{
    if (!PowerToSwitch)
        coutError << "No power!";
    else
        SwitchOn = true;
}

因为有宏,会变成这样:

void LightSwitch::TurnOn()
{
    if (!PowerToSwitch)
        if (VERBOSITY_SETTING >= VERBOSITY_ERROR)
            ods() << "No power!";
        else
            SwitchOn = true;
}

这不是 if 语句的预期功能。

现在,我了解了一种正确修复此宏的方法,因此它不会导致此问题,但我想对代码进行审核并找到任何具有“if (... ) coutError

我可以使用任何语言/工具来找到它,我只是想知道最好的方法。

【问题讨论】:

    标签: c++ parsing macros


    【解决方案1】:

    您可以尝试 - 临时 - 将宏修改为类似的内容,然后看看哪些内容无法编译...

    #define coutError {} if (VERBOSITY_SETTING >= VERBOSITY_ERROR) ods()
    

    'else' 子句现在应该给出错误。

    【讨论】:

    • 很好,但我认为他也可能对没有其他条件的 if 有问题?不过不确定。
    • 这是个好主意,但我认为您的线路不会引起正确的问题。 else 仍将附加到 #defined if 语句。
    • 我认为这是需要的:#define coutError {} ods()
    【解决方案2】:

    不要费心去寻找代码中发生逻辑错误的所有位置——从源头上解决问题!更改宏,以免出错:

    #define coutError if(VERBOSITY_SETTING < VERBOSITY_ERROR); else ods()
    

    请注意,我在这里所做的是反转测试,为then 子句添加了一个空语句,并将输出对象放在else 子句中。这仍然允许您在宏之后使用&lt;&lt; foo &lt;&lt; bar,并且如果您有一个属于不同if 语句的尾随else 子句,它将正确匹配,因为它像这样扩展:

    if(foo)
        coutError << bar;
    else
        baz();
    

    变成

    if(foo)
        if(VERBOSITY_SETTING < VERBOSITY_ERROR)
            ;
        else
            ods() << bar;
    else
        baz();
    

    【讨论】:

    • 这是一个很好的修复;甚至比我要做的更简单。但是,问题的重点是通过修复问题来确定是否会出现任何错误。
    【解决方案3】:

    我认为宏的所有良好用法都以'{'或';'开头。

    所以试试这个正则表达式:

    [^{;]\s*coutError
    

    您需要打开多行匹配并搜索整个文件。

    您可能需要获取更多的东西,以便找到有问题的行 :-)

    如果我们能找出一些会正确失败的东西,那么改变宏是一个好主意。可能是一个块后跟条件运算符:

    #define coutError {} (VERBOSITY_SETTING >= VERBOSITY_ERROR)?(ods()):(nullstream()) 
    

    (但确实需要实现一个 nullstream() 运算符。)

    (或者完全暂时摆脱条件 - 正如您所建议的那样,是对另一个答案@Roddy(当前选择的答案)的评论)。

    附言我知道你没有问,但是包装宏以使其安全的一种简单方法是使用 do {} while(false) 循环。

    【讨论】:

    • 我不认为你可以将这个特定的宏包装在任何东西中,让它不会遇到这个问题。这也会捕获一些误报,即“if (...) coutError
    • 正则表达式 find = new Regex(@"if[^{};]+coutAgent[^{};]+;[^{};]+else", RegexOptions.Singleline);似乎可以解决问题
    【解决方案4】:

    我在上面的 cmets 中看到您正在考虑在宏中使用模板,但我还不能发表评论(我还差 9 分),所以...

    什么阻止你做

    #define CoutError(s) { if (VERBOSITY_SETTING >= VERBOSITY_ERROR){ ods(s); } }
    

    然后

    void LightSwitch::TurnOn()
    {
        if (!PowerToSwitch)
            CoutError("No power!");
        else
            SwitchOn = true;
    }
    

    然后重新定义 ods 以接受一个字符串,或者如果你不能,那么只需定义一个 OdsHelper 函数,它接受一个字符串,其主体只是 ods

    如果没有明显的收获,我不会使用试图模仿

    你真的需要

    你真的需要为这个简单的行为引入一个模板吗?

    最后一件事 - 不要使用宏。

    【讨论】:

    • 嗯,问题更多的是它在模仿 cout。例如:coutError
    • 太好了,现在我可以评论了 :) 你应该尝试重构框架,至少删除它更成问题的宏并尝试为它们建立标准。一个共同的标准是宏在块中。告诉你的团队并试图说服他们。如果你不能,那么你就被卡住了:)
    【解决方案5】:

    我认为真正的问题是宏的使用,而不是经过预处理的代码。但我认为这不是您要寻找的答案。

    我会找到一种完全不使用宏的方法——如果你确实使用条件编译,你可以在调用 ods() 时这样做——取决于一些#define,它可以使用你想要的任何功能。

    只是我的 $.02

    【讨论】:

    • 我打算修复它的方法是使用模板,所以: typedef ods coutError;
    【解决方案6】:

    正则表达式搜索?

    【讨论】:

    • 好吧,问题在于 if 中的内容可能很复杂,而 coutError 之后的语句也可能很复杂。可以使用什么正则表达式?
    猜你喜欢
    • 2015-05-25
    • 2017-02-18
    • 2012-03-06
    • 1970-01-01
    • 2012-08-28
    • 2012-07-24
    • 2020-12-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多