2

我有一个看起来像这样的宏:

#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 < < ...; else" 以查明是否有任何其他情况发生这种情况,以确保在修复宏时,它确实是正确的功能。

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

4

6 回答 6

2

您可以尝试 - 暂时 - 将宏修改为这样的东西,看看什么不能编译......

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

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

于 2008-12-29T21:33:33.853 回答
2

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

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

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

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

变成

if(foo)
    if(VERBOSITY_SETTING < VERBOSITY_ERROR)
        ;
    else
        ods() << bar;
else
    baz();
于 2008-12-29T22:05:18.453 回答
1

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

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

[^{;]\s*coutError

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

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

或者,如果我们可以解决一些会正确失败的问题,那么更改宏是一个好主意。可能是一个块后跟条件运算符:

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

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

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

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

于 2008-12-29T21:47:59.957 回答
1

我在您上面的评论中看到您正在考虑在宏中使用模板,但我还不能发表评论(我还差 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 << inString?

如果没有明显的收获,我不会尝试模仿 << 语法的宏。至少对于模拟函数语法的宏,我们使用得更多,而且我们知道我们必须编写块来防止出现奇怪的问题。

你真的需要 << 语法吗?

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

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

于 2008-12-29T21:57:00.187 回答
0

我认为真正的问题是宏的使用——而不是被预处理的代码。但我认为这不是您正在寻找的答案。

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

只是我的 $.02

于 2008-12-29T21:19:31.823 回答
0

正则表达式搜索?

于 2008-12-29T21:25:24.277 回答