删除“if”语句中的花括号是否有例外情况?

6
我是一名计算机科学专业的学生,不久前我们的教授向我们解释了在C语言中当只有一条语句时,可以删除大括号的写法:
if (a)
  do b

但我们不能做这样的事情:
if(a)
  do b
  do c

因为那样会执行多个语句。

但是它也告诉我们有一个例外,关于去掉花括号的事情,即使只有一个语句也不能这样做。我搜索了很多,但我找到的唯一一件事是在do-while循环中无法这样做,但我们正在讨论if语句,有什么帮助吗?

编辑:我们也在谈论嵌套的if语句,也许是关于那个的问题?


从未听说过或遇到需要在 if 语句中使用 {} 的情况。 - Fiddling Bits
我相信你也可以删除 do-while 循环的大括号。 - Quentin
也许你的教授的异常处理是出于风格而非语法原因。 - Ian Abbott
8
当一个if语句中包含多个语句时,需要使用大括号将它们括起来形成代码块。否则,在条件为真时,只有第一条语句会被执行,而后面的语句将在任何情况下都会被执行。这种问题称为悬挂else问题,可通过在if语句和else语句周围添加大括号来解决。C语言是一种可能出现悬挂else问题的编程语言。 - user2201041
一个变量声明如 int n = 1; 是一个单独的语句,但如果放在花括号中 { int n = 1; },它就属于另一个上下文,并且无法从该上下文的其余部分访问。 - Giovanni Cerretani
4个回答

12

你的教授可能在谈论这样一种情况:

if (a)
    if (b)
        printf("a and b\n");
else  // this goes with the inner "if"
    printf("not a\n");

与缩进所示相反,else 与外部的 if 语句无关,而是与内部的 if 语句相关。在这种情况下,您需要向外部 if 的主体添加花括号,以使 else 正确关联:

if (a) {
    if (b)
        printf("a and b\n");
}
else
    printf("not a\n");

最好总是使用大括号来包裹条件和循环结构的主体,以防止这种歧义和随之而来的错误。


2
这被称为悬挂的else歧义,编译器被构建以匹配最近的if - Paul Ogilvie
好的,那看起来很不错,很可能是这样;但也许会出现编译错误?编辑:我还在考虑在“仅限语句”的情况下声明一个变量,这将基本上销毁新变量,使其无用。 - WhiteNoise
@cmaster 好的,谢谢。我很确定这是悬挂else问题,因为我们也在讨论嵌套的if语句。 - WhiteNoise
@WhiteNoise 顺便说一下: 谷歌一下"goto fail bug",可以看到一个备受关注的、真实世界的例子 ^^ - cmaster - reinstate monica
@WhiteNoise 不要理会我关于 if() 不可能出现编译错误的评论。这是错误的。请参考 Antti Haapala 的答案(https://dev59.com/p6_la4cB1Zd3GeqPyMix#53284483)了解详情。我现在将删除我的错误评论。 - cmaster - reinstate monica

2

虽然可以使用没有花括号的单个语句,但如果您没有任何语句该怎么办:

if (ham)
    int eggs = spam();

由于if需要保护恰好一个语句,所以无法编译。

if (ham) {
    int eggs = spam();
}

这里有一个带初始化声明并调用函数的复合语句;以及0个语句。当然,如果变量在其他地方没有使用,这并没有什么用...


太棒了,你实际上发现了一个语法上的不可能性 :-) - cmaster - reinstate monica
@cmaster 但这不是“仅有一条语句” ;) - Antti Haapala -- Слава Україні
变量定义不也是一个单独的语句吗?只不过不能作为 if() 的主体语句而已。 - cmaster - reinstate monica

1
但它也告诉我们,即使只有一个语句,我们也不能删除花括号。我相信你的教授试图教授你最佳实践。尽管从C语言的角度来看,我们可以不使用花括号编写if语句,但我们永远不应该这样做。这不仅仅是主观个人风格偏好的问题,而是程序安全性的问题。因为很容易写出像这样的错误:
if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
    goto fail;
    goto fail;  /* MISTAKE! THIS LINE SHOULD NOT BE HERE */

第二个 goto 语句将总是被执行,这并不是本意。我敢说,每一个允许这种写法的 C 程序员都曾经写过这个 bug。在完全停止使用这种写法之前,我自己也偶尔会犯这个错误。

出于安全考虑,著名的编码标准,如 CERT-C 和 MISRA-C,禁止使用没有花括号的 if 等语句。请参见 CERT-C EXP19-C 和 MISRA-C:2012 规则 15.6。


0

使用这个语法的宏(多行)进行调试很困难。您必须查看预处理的C代码以识别问题。

#define MULTISTATEMENT a=5;\
                       b=5;
#include <stdio.h>

int main() {
   int a = 10, b = 10;
   if(a == 10)
       MULTISTATEMENT
   else
       a = 3;
   printf("a = %d b = %d\n", a, b);
   return 0;
}

这段代码会产生错误。请将{}放在宏定义周围或if语句周围以编译此代码。


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