Почему «dangling-else» выдает предупреждение?

У меня есть программа. Где-то в программе у меня есть этот код:

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: warning: add explicit braces to avoid dangling else [-Wdangling-else]

Почему именно это предупреждение и необходимо? Я знаю, что else идет к ближайшему else-менее if, и предпочитаю по возможности избегать фигурных скобок (для удобочитаемости). Это clang, gcc выдает аналогичную ошибку.

Избегать фигурных скобок (для удобочитаемости??) — большая ошибка. Всегда используйте фигурные скобки, если только это не очень простой оператор if без else.

pmacfarlane 05.08.2023 00:37

добавь -Wno-dangling-else.

Stanislav Volodarskiy 05.08.2023 00:37

Смотрите , почему опускать фигурные скобки считается плохой практикой?

Barmar 05.08.2023 00:38

это может ввести в заблуждение и сбить с толку, если отступы в коде сделаны по-другому.

Cj Y 05.08.2023 00:39

@StanislavVolodarskiy Это должен быть ответ.

Barmar 05.08.2023 00:41

@pmacfarlane: избегание фигурных скобок не является серьезной ошибкой. Это один из инструментов для уменьшения ошибок. Он имеет положительные и отрицательные стороны. Есть и другие инструменты, тоже с плюсами и минусами. Какие инструменты использовать – это выбор.

Eric Postpischil 05.08.2023 00:48

@EricPostpischil Я не имел в виду ошибку как ошибку. Очевидно, что это действительно так. Но хорошо известно, что он хрупкий и запутанный — он никогда не пройдет проверку кода в любом месте, где я когда-либо работал.

pmacfarlane 05.08.2023 00:54

@pmacfarlane: Это ваше мнение и выбор места работы. Это не универсально и не факт. Однострочный оператор с if не сбивает с толку.

Eric Postpischil 05.08.2023 01:02

Одна строка, содержащая макрос, может быть ошибкой, а может и не быть.

stark 05.08.2023 14:17
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
9
76
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Почему «dangling-else» выдает предупреждение?

Потому что иногда такой код пишется по ошибке:

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

Компилятор распознает шаблон и не может быть уверен, есть ли ошибка, поэтому он предупреждает вас.

Это вряд ли произойдет в простом коде, но учтите:

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

В этом случае человек, который позже добавляет else, намереваясь использовать его для A, может не увидеть промежуточный if вместо B, когда он добавляет else. Это может быть прокручено из окна их редактора. Итак, когда компилятор видит этот шаблон и включено предупреждение dangling-else, он предупреждает вас.

(Было бы неплохо, если бы компилятор учитывал отступы и, если отступы были постоянными во всей программе, а отступы else соответствовали его совпадениям if, не выдавал это предупреждение.)

«Было бы неплохо, если бы компилятор учитывал отступы и, если отступы были одинаковыми во всей программе, а отступы else соответствовали их совпадениям, если бы он не выдавал это предупреждение». - нет, с тем, насколько распространены автоформатеры и автоматические отступы, слишком часто висячие elses просто автоматически выравниваются по if, которым они соответствуют, а не по if, которым они должны были соответствовать. Вы не можете доверять отступу, чтобы он соответствовал намерению.

user2357112 05.08.2023 00:57

@ user2357112: автоматический отступ также помогает пользователям раньше обнаруживать ошибки и обеспечивать соответствие написанного кода предполагаемому коду. Добавление фигурных скобок создает беспорядок, который в некоторых случаях приводит к ошибкам.

Eric Postpischil 05.08.2023 01:04

Конечно, автоматический отступ полезен. Я просто говорю, что, поскольку согласованный отступ так часто происходит автоматически, это не лучший индикатор того, что висячие elses соответствуют тому, с чем они должны были совпадать.

user2357112 05.08.2023 01:08

@user2357112: user2357112: Но предупреждение компилятора о зависании-иначе раздражает некоторых людей, поэтому они его не используют. Неиспользованный инструмент не имеет ценности. Улучшение его с учетом отступов может уменьшить неудобства и сделать его достойным использования.

Eric Postpischil 05.08.2023 01:24

Я не совсем понимаю вашу точку зрения @ user2357112. Для меня автоматический отступ часто позволяет мне узнать, на какой if в этом примере идет else, и я могу уловить это таким образом.

user129393192 05.08.2023 01:54

Я ненавижу идею компилятора, даже знающего об отступах. Со всем этим должны справиться препроцессор и лексер. Пробел не имеет значения в C, и мне это нравится.

pmacfarlane 05.08.2023 02:03

@ user129393192: Да, здесь может помочь автоматический отступ. Автоматический отступ полезен! Но если бы висячие else-предупреждения работали так, как предлагает Эрик, то автоматический отступ эффективно отключил бы висячие else-предупреждения. Компилятор предположил бы, что каждый else соответствует if, которому он должен соответствовать, основываясь на отступе, который был написан инструментом, а не человеком, который написал оборванный else.

user2357112 05.08.2023 02:06

Я понимаю. Я не уверен, что вы используете, но я использую eMac и активно вижу автоматический отступ в игре и сам проверяю его @ user2357112

user129393192 05.08.2023 02:33

@pmacfarlane, тогда ты должен ненавидеть Python. Но я предпочитаю отступ фигурным скобкам, и любой здравомыслящий человек в любом случае хорошо сделает отступ, даже если он не имеет синтаксического значения.

Mark Ransom 05.08.2023 04:12

OP заявляет: «и предпочитаю избегать фигурных скобок, когда это возможно (для удобочитаемости)»

Это приводит к изучению потока представленного кода. Для удобочитаемости этот поток можно было бы выразить без обращения к else, оборванному или нет:

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?
}

Немного комментариев и простая логика облегчают понимание этой процедуры. Это обходит вопрос о любых болтающихся еще.

Ваш ответ мне очень помог. Код теперь 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 05.08.2023 19:46
Ответ принят как подходящий

Отступы не имеют значения в C. Каждое из следующего в точности идентично:

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

и

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

и

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

Компилятор предупреждает вас, что людям это кажется двусмысленным, и вы должны явно добавить фигурные скобки, чтобы ваш код был очевиден.

Приняли, потому что оно было самым прямым и ясным. Вы специально указали, что отступ не имеет значения в C, и поэтому компилятор делает это. Спасибо. Вы разъяснили мне это.

user129393192 05.08.2023 19:50

Другие вопросы по теме