如果没有花括号的if和else

39

我希望以下代码可以编译通过。然而,Clang和VC++都在包含else的那一行报错。

void MyFunction(std::int32_t& error)
{
   std::int32_t variable = 0;
   if(GetSomething())
      error = EOK;
   else
      error = ERROR;
}

如果我在error = EOK;周围加上花括号,那么它就可以通过编译。为什么VC++会说:

illegal else without matching if


我的完整代码如下,将std::uint32_t替换为typedef,但在VC++中仍然会出现相同的错误。

using sint32 = int;

#define ERROR 5;
#define EOK 0;

bool GetSomething();

void MyFunction(sint32& error)
{
   sint32 variable = 0;
   if (GetSomething())
      error = EOK;
   else
      error = ERROR;
}

80
我嗅到了宏观鼠。 - Hans Passant
2
什么是EOK(或GetSomething)?也许它是一些奇怪的宏定义。 - marcinj
13
这是为数不少的例子之一,说明为什么不应使用宏。 - bames53
11
@bames53 更加重要的是,需要给你一个示例,说明为什么在if-else控制语句中应该使用大括号。 - silvo
9
这是一个错误的宏定义,与需要大括号无关。在这里,error = GetSomething() ? EOK : ERROR;也会导致编译错误,加入大括号也不能解决问题。 - Marc van Leeuwen
显示剩余4条评论
3个回答

94
如果您对EOK的定义如下所示: #define EOK 0; 那么它会导致这种类型的错误,因为它在else被执行之前强制终止了if语句,使其成为一个没有匹配的if的else。编译器在宏替换后看到此代码:
if(GetSomething())
    error = 0;;
else

17
最好使用常量而不是宏! - Mgetz
61
啊,以分号结尾的宏。纯恶心。 - ApproachingDarknessFish
27
第245个原因:没有使用大括号的控制语句很容易出问题... - sapi
一般来说,您可以通过明确检查预处理文件来调试预处理器问题 - 在VC中,使用CL /P/E。@sapi:尽管可能性小得多,但您仍然可能会被#define EOK 0}挫败。 - Jonathan

14

这里是一个可能的解决方法:

enum
{
    EOK = 0,
    ERROR = 5
};

请注意,以E开头的标识符后面跟着大写字母或数字,这些标识符被<cerrno>保留用作宏名称。为避免名称冲突,请考虑使用不同的命名约定来命名您的错误。


2
最好将其作为类枚举以获得更好的命名空间,这样它就不必一直以 E 开头了 :D - Benjamin Gruenbaum

0
为了更简单和高效,您可以这样做:
error = (GetSomething()) ? 0 : 5 ;

如果你想按照Matt所说的使用枚举,那么它就变成了:

error = (GetSomething()) ? enum.EOK : enum.ERROR ;

错误 = (GetSomething()) ? enum.EOK : enum.ERROR; - karim
我对你的说法提出质疑,认为这并不更有效率。编译器应该生成相同的代码。 - Sebastian Redl
Sebastian,一行代码对于编译器和开发人员来说更加容易(同时也能减少复杂性的一面)。 - karim
2
一行代码并不一定更容易让开发者理解——这取决于这行代码的复杂程度。对于编译器来说,它绝对不会更容易——无论如何,编译器都会将其解析成树形结构,然后优化器和代码生成器会使用该结构进行处理,甚至可能是更加深度加工过的形式。 - Sebastian Redl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接