“dangling-else” 为什么会发出警告?

huangapple go评论113阅读模式
英文:

Why does "dangling-else" emit a warning?

问题

我有一个程序。在程序的某处,我有这段代码:

```c
int
read_n(char *cp, int n)
{
  int nread;
  if ((nread = read(STDIN_FILENO, cp, n)) != n)
    if (nread == -1)
      die(DIE_ERROR_FMT, "failed reading input");
    else
      return nread;
  return n;
}

并且像这样编译我的程序:

cc -std=c99 -Wall -Wextra -Wshadow -Wpedantic prog.c -o prog

我得到了以下警告:

le.c:343:5: 警告:添加显式的大括号以避免悬挂的 else [-Wdangling-else]

为什么这会是一个警告,而且为什么有必要添加大括号呢?我知道else会匹配最近的没有elseif,并且尽量在可能的情况下避免使用大括号(以提高可读性)。这是clanggcc也会产生类似的错误。


<details>
<summary>英文:</summary>

I have a program. Somewhere in the program, I have this code:

int
read_n(char *cp, int n)
{
int nread;
if ((nread = read(STDIN_FILENO, cp, n)) != n)
if (nread == -1)
die(DIE_ERROR_FMT, "failed reading input");
else
return nread;
return n;
}

and compiling my program like this:

cc -std=c99 -Wall -Wextra -Wshadow -Wpedantic prog.c -o prog

I get:

le.c:343:5: warning: add explicit braces to avoid dangling else [-Wdangling-else]

Why exactly is this a warning, and necessary? I know that the `else` goes to the nearest `else`-less `if` and prefer to avoid braces when possible (for readability). This is `clang`, `gcc` gives a similar error.

</details>


# 答案1
**得分**: 3

在C语言中,缩进不重要。以下每个示例都完全相同:

```c
if (a())
if (b())
foo();
else
bar();

if (a)
  if (b)
    foo();
  else
    bar();

以及

if (a)
  if (b)
    foo();
else
  bar();

编译器警告你,这对人类来说似乎是模棱两可的,你应该明确地添加大括号以使你的代码明显。


编辑:正如评论中所指出的,我的答案明确说明了缩进不重要,并且不能帮助消除else应该属于哪个if的歧义。

值得一提的是,不仅是前导缩进,而且所有空白字符都不重要。C语言(以及大多数基于C语法的语言)不区分空格、制表符和换行符。

以下是与上述版本完全相同的几个更多示例:

if (a) if (b) foo(); else bar();
if (a)
  if (b) foo(); else bar();
if (a)
  if (b) foo();
else bar();

再次强调,编译器对此没有歧义,但许多人会难以理解else应该放在哪里。

英文:

Indentation doesn't matter in C. Each of the following is exactly identical:

if a()
if b()
foo();
else
bar();

and

if (a)
  if (b)
    foo();
  else
    bar();

and

if (a)
  if (b)
    foo();
  else
    bar();

The compiler is warning you that this appears ambiguous to humans, and you should explicitly add braces to make your code obvious.


Edit: As noted in a comment, my answer makes it clear that indentation doesn't matter, and doesn't help disambiguate which if the else was intended to belong to.

It's worth mentioning that it's not only leading indentation but all whitespace that doesn't matter. C (and most languages based on C syntax) makes no difference between spaces, tabs, and newlines.

Here are a few more versions that are exactly identical to the above versions:

if (a) if (b) foo(); else bar();
if (a)
  if (b) foo(); else bar();
if (a)
  if (b) foo();
else bar();

Again, there is no ambiguity for the compiler here, but many humans will struggle to understand where the else goes.

答案2

得分: 2

OP 表示:"并且尽量避免在可能的情况下使用大括号(以提高可读性)"

这导致需要检查所呈现的代码的流程。为了提高可读性,可以在不使用 else 的情况下表达此流程,无论是否悬挂:

int
read_n(char *cp, int n)
{
  int nread = read(STDIN_FILENO, cp, n); // 简单表达(即未嵌套在“if”中)

  if (nread == n) // 期望的结果
    return n;

  if (nread != -1) // 次优的结果,但不是完全失败
    return nread;

  // 对完全失败做出反应
  die(DIE_ERROR_FMT, "failed reading input");
  return -1; // 或者执行是否已经停止?
}

少量注释和简单的逻辑流使这个例程更容易理解。这个方法避免了任何“悬挂的else”问题。

英文:

OP states: "and prefer to avoid braces when possible (for readability)"

This leads to examining the flow of the presented code. For readability, this flow could be expressed without recourse to else, dangling or not:

int
read_n(char *cp, int n)
{
  int nread = read(STDIN_FILENO, cp, n); // simply expressed (ie. not nested in an &#39;if&#39;)

  if (nread == n) // desired result
    return n;

  if (nread != -1) // suboptimal result, but not total failure
    return nread;

  // react to complete failure
  die(DIE_ERROR_FMT, &quot;failed reading input&quot;);
  return -1; // or is execution already stopped?
}

A sprinkling of comments and a simple flow of logic make this routine easier to understand. This skirts the issue of any dangling else.

答案3

得分: 1

"悬挂else"为什么会发出警告?

因为有时候会错误地编写这样的代码:

if (A)
    if (B)
        C;
else // 本意是应用于A,但应用于B。
    D;

编译器识别到这种模式,并不能确定是否存在错误,所以它会发出警告。

在简单的代码中,这种情况不太可能发生,但考虑以下情况:

if (A)
    if (B)
    {
        几十行代码...
    }

在这种情况下,稍后添加else的人,本意是要为A添加,但当他们添加else时,可能没有看到中间的if用于B。它可能已经滚动出了他们的编辑器窗口。因此,当编译器看到这种模式并且启用了"dangling-else"警告时,它会发出警告。

(如果编译器考虑了缩进,并且如果整个程序的缩进保持一致,else的缩进与其匹配的if一致,那么它可能不会发出这个警告会更好。)

英文:

> Why does "dangling-else" emit a warning?

Because sometimes code like this is written by mistake:

if (A)
    if (B)
        C;
else // Intended to apply to A but applies to B.
    D;

The compiler recognizes the pattern and cannot be sure whether or not there is a mistake, so it warns you.

This is unlikely to occur in simple code, but consider:

if (A)
    if (B)
    {
        Several dozen lines of code…
    }

In this case, the person who adds the else later on, intending it for the A, might not see the intervening if for B when they are adding the else. It might be scrolled out of their editor window. So, when the compiler sees this pattern, and the dangling-else warning is enabled, it warns you.

(It might be nice if the compiler considered indentation, and, if the indentation were consistent throughout the program and the indentation of the else were consistent with its matching if, did not emit this warning.)

huangapple
  • 本文由 发表于 2023年8月5日 06:30:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/76839412.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定