0

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.

Barmar
  • 741,623
  • 53
  • 500
  • 612
user129393192
  • 797
  • 1
  • 8
  • 5
    Avoiding braces (for readability??) is a massive mistake. Always use braces, unless it is for a very simple `if` statement with no `else`. – pmacfarlane Aug 04 '23 at 22:37
  • add `-Wno-dangling-else`. – Stanislav Volodarskiy Aug 04 '23 at 22:37
  • 2
    See [why is it considered a bad practice to omit curly braces?](https://stackoverflow.com/questions/359732/why-is-it-considered-a-bad-practice-to-omit-curly-braces?lq=1) – Barmar Aug 04 '23 at 22:38
  • it can be very misleading and confusing if the code indentation is done differently. – user9035826 Aug 04 '23 at 22:39
  • @StanislavVolodarskiy That should be an answer. – Barmar Aug 04 '23 at 22:41
  • 2
    @pmacfarlane: Avoiding braces is not a massive mistake. It is one tool for reducing errors. It has positives and negatives. There are other tools, also with positives and negatives. Which tools to use is a choice. – Eric Postpischil Aug 04 '23 at 22:48
  • 4
    @EricPostpischil I didn't mean mistake as in an error. It's obviously valid. But it's well known to be fragile and confusing - it would never pass a code review at anywhere I've ever worked. – pmacfarlane Aug 04 '23 at 22:54
  • 2
    @pmacfarlane: That is your opinion and choices of where you have worked. It is not universal and is not a fact. A single line statement with an `if` is not confusing. – Eric Postpischil Aug 04 '23 at 23:02
  • 1
    A single line containing a macro may or may not be an error. – stark Aug 05 '23 at 12:17

3 Answers3

3

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.

user229044
  • 232,980
  • 40
  • 330
  • 338
  • 1
    Accepted because it was the most direct and clear. You stated specifically that indentation doesn't matter in C and that's why the compiler is doing this. Thank you. You made it clear for me. – user129393192 Aug 05 '23 at 17:50
2

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 'if')

  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, "failed reading input");
  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.

Fe2O3
  • 6,077
  • 2
  • 4
  • 20
  • Your answer helped me a lot. The code is now `int read_n(char *cp, int n) { int nread = read(STDIN_FILENO, cp, n); if (nread != -1) return nread; else die(DIE_ERROR_FMT, "failed reading input"); }`. – user129393192 Aug 05 '23 at 17:46
  • 1
    @user129393192 Glad to help. Note, though, that the `else` after the `return` is pointless... Return is return and the flow has changed tracks... Suggest that you get rid of that `else`... – Fe2O3 Aug 05 '23 at 21:13
  • 1
    You're right. Thanks. – user129393192 Aug 05 '23 at 21:14
1

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.)

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • 1
    "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." - nah, with how common autoformatters and auto-indentation are, it's too common for dangling elses to just get automatically aligned to the `if` they match instead of the `if` they were supposed to match. You can't trust the indentation to match the intent. – user2357112 Aug 04 '23 at 22:57
  • 1
    @user2357112: The automatic indentation also helps users catch errors earlier and ensure the code written matches the code intended. Adding braces adds clutter which, in some code, contributes to errors. – Eric Postpischil Aug 04 '23 at 23:04
  • Sure, auto-indentation is useful. I'm just saying that because consistent indentation so often happens automatically, it's not a good indicator for dangling elses matching what they were supposed to match. – user2357112 Aug 04 '23 at 23:08
  • @user2357112: But the compiler’s dangling-else warning is a nuisance for some people, so they do not use it. An unused tool has no value. Improving it to consider indentation could reduce the nuisance and make it worth using. – Eric Postpischil Aug 04 '23 at 23:24
  • I do not quite see your point @user2357112. For me, the auto-indentation often lets me know which `if`, in this example, the `else` goes onto, and I can catch it that way – user129393192 Aug 04 '23 at 23:54
  • I hate the idea of a compiler even _knowing_ about indentation. The pre-processor and lexer should deal with all that. White-space has no meaning in `C` and I like it. – pmacfarlane Aug 05 '23 at 00:03
  • @user129393192: Yes, that's a way auto-indentation can help here. Auto-indentation is useful! But if the dangling else warnings worked the way Eric suggests, then auto-indentation would effectively disable dangling else warnings. The compiler would assume every `else` matched the `if` it was supposed to match, based on indentation that was written by a tool, not by the human who wrote the dangling `else`. – user2357112 Aug 05 '23 at 00:06
  • I see. I’m not sure you use, but I use eMacs, and actively can see the auto indentation at play and verify it myself @user2357112 – user129393192 Aug 05 '23 at 00:33
  • @pmacfarlane you must hate Python then. But I prefer indentation to braces, and any sane person will indent well anyway even if it's not syntactically significant. – Mark Ransom Aug 05 '23 at 02:12