Какая сторона (левая или правая) оператора && (и) вычисляется в C ++

Какой порядок вычисляется оператором and &&

Например, следующий код

if (float alpha = value1-value2 && alpha > 0.001)
    //do something

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

Любая идея?

Спасибо


person zenna    schedule 20.01.2010    source источник
comment
Странный вопрос, у меня нет учебника.   -  person zenna    schedule 20.01.2010
comment
См .: stackoverflow.com/questions/136548/   -  person Shog9    schedule 20.01.2010
comment
Какой смысл сравнивать целое число с литералом с плавающей запятой? Вы должны написать alpha > 0. Его легче печатать, он делает то же самое и более четкий. В качестве альтернативы выполните сравнение с числами с плавающей запятой.   -  person David Thornley    schedule 20.01.2010
comment
вы правы, это должен был быть поплавок.   -  person zenna    schedule 21.01.2010


Ответы (14)


Это разбирается как:

if (int alpha = (value1-value2 && (alpha > 0.001)))

... потому что && имеет более высокий "приоритет синтаксического анализа", чем = - что, вероятно, не то, что вам нужно. Пытаться:

int alpha = value1-value2; 
if (alpha && (alpha > 0.001))
person Kornel Kisielewicz    schedule 20.01.2010
comment
В подвыражении не может быть объявления. Ваша пробная версия недействительна. - person AnT; 20.01.2010
comment
Конечно, еще одна ошибка в этом ответе - это попытка сравнить приоритет && с приоритетом =. В приведенном выше синтаксисе = не является оператором. У него нет приоритета. - person AnT; 20.01.2010
comment
@AndreyT: Исправлено, вроде как. Термин «приоритет» использовался в отношении приоритета лексического лексема, а не оператора. - person Kornel Kisielewicz; 20.01.2010
comment
if ( alpha > 0.001 ) делает то же самое - person Potatoswatter; 21.01.2010

Суть здесь в том, что то, что вы пытаетесь выразить, не может быть выражено одним логическим условием с включенным в него объявлением alpha (несмотря на то, что утверждают некоторые другие ответы).

В других ответах вам уже объяснялось, что ваше условие не анализируется так, как вы думаете, что оно анализируется, хотя во многих ответах есть очевидная ошибка ссылки на приоритет оператора = в условии, хотя на самом деле там вообще нет оператора =. Правильное объяснение состоит в том, что когда вы объявляете переменную в условии if, синтаксис аналогичен объявлению с инициализатором, поэтому все это анализируется так же, как

int alpha = value1 - value2 && alpha > 0.001;

будет проанализирован, т.е. это объявление int alpha, инициализированное с помощью value1 - value2 && alpha > 0.001. В нем нет оператора =. И я надеюсь, что теперь вы понимаете, почему компилятор говорит, что вы читаете неинициализированную переменную в выражении инициализатора. Компилятор подал бы такую ​​же жалобу на следующее объявление

int alpha = alpha; // reading uninitialized variable

по той же причине.

Чтобы достичь того, что вы буквально пытаетесь выразить, вы должны либо заранее объявить alpha

int alpha;
if ((alpha = value1 - value2) && alpha > 0.001) {
  // whatever 
}

или разделите свой if на два

if (int alpha = value1 - value2) 
  if (alpha > 0.001) {
    // whatever 
  }

Однако, поскольку второе условие уже требует, чтобы alpha было больше, чем 0, нет особого смысла даже проверять первое, поэтому наиболее значимым вариантом было бы просто свести все это к

int alpha = value1 - value2;
if (alpha > 0.001) {
  // whatever 
}

Конечно, как уже отмечали другие, сравнение значения int со значением 0.001 является допустимым, но довольно странным делом. Просто сделать

int alpha = value1 - value2;
if (alpha > 0) {
  // whatever 
}
person AnT    schedule 20.01.2010

Левая сторона всегда оценивается первой. Проблема здесь в приоритете операторов. Посмотрите, не работает ли это лучше:

if ((int alpha = value1-value2) && (alpha > 0.001))
person Jerry Coffin    schedule 20.01.2010
comment
Если я не ошибаюсь, объявление alpha, подобное этому, не разрешено в теле if, когда оно является частью более крупного выражения. - person James McNellis; 20.01.2010
comment
@ Джеймс: навскидку, я не помню, но вы могли быть правы. В данных обстоятельствах я бы, вероятно, использовал: int alpha = value1-value2; if (alpha>0.001) Как написано, код также включает избыточное сравнение с нулем. - person Jerry Coffin; 20.01.2010
comment
Согласно этому ответу здесь это запрещено: stackoverflow.com/questions/1516919/1516966#1516966 (взял меня некоторое время, чтобы найти это). MSVC ++ 2008 и Intel C ++ 11.1 также отвергают его. - person James McNellis; 20.01.2010

После выяснения того, как это работает (в образовательных целях), не делайте этого. Не смешивайте инициализацию / присвоение переменных и сравнения в одном операторе.

Лучше, если каждый оператор будет либо «командой», либо «запросом».

И будет намного, намного лучше, если условие внутри «if» будет очень четко читаемым и однозначно логическим. Не целое число, ничего, просто булево.

Первая часть вашего условия - целое число. Затем вы выполняете и с помощью bool. Вы вызываете конверсию без необходимости. Дайте if и условные операторы именно то, что они просят: bools.

person Daniel Daranas    schedule 20.01.2010

Отвечая на вопрос в заголовке, это зависит от типов операндов.

Для встроенных типов && закорачивает, что означает, что LHS оценивается, а если оно ложно, то RHS вообще не оценивается.

Для определяемых пользователем типов, которые имеют перегрузку operator&&, короткое замыкание не выполняется. Обе стороны оцениваются в неопределенном порядке, а затем вызывается функция.

Я думаю, что другие ответили на ваш вопрос.

person Steve Jessop    schedule 20.01.2010
comment
Вот почему я рекомендую разработчикам C ++, которые перегружают &&, || или ,, получить образование, если они младшие, или застрелить или уволить, если они старше, в зависимости от того, что лучше работает в соответствии с местными законами. - person David Thornley; 20.01.2010
comment
@ Дэвид Торнли: В общем, неправда. Если класс, для которого эти операторы перегружены, не имеет очевидной логической семантики, то вам не следует (и не может) делать никаких предположений о поведении перегруженного &&. - person AnT; 20.01.2010
comment
@AndreyT: Если нет очевидной логической семантики, не перегружайте случайные операторы. В любом случае тот факт, что && перегружен, обычно не сразу очевиден, и перегрузка изменяет фундаментальное поведение оператора, удаляя точку последовательности. Если я не могу взглянуть на утверждение и увидеть, где находятся точки последовательности, значит, кто-то сильно облажался. - person David Thornley; 20.01.2010
comment
@ Дэвид Торнли: Вы думали, что вы говорите об отсутствии оценки короткого замыкания перегруженного &&. Точка следования - это другой вопрос. Он скорее заменяется группой совершенно разных точек последовательности, расположенных по-разному. Я согласен, это может быть проблемой. - person AnT; 20.01.2010
comment
@ Дэвид: Я почти согласен со стрельбой, но перегрузка operator, может быть нормой, когда вы, по сути, изобретаете DSL, погруженный в C ++. Просто убедитесь, что при использовании очевидно, что это не оператор запятой вашей бабушки. Думаю, то же самое можно сказать и о && и ||. Это математические операторы с самым низким приоритетом, что, возможно, удобно, если вам нужно вмешиваться в значения чего-либо (приоритет оператора потока ‹< настолько произвольный). Как говорит AndreyT, точки последовательности еще есть. Один (ну, два) на каждый вызов функции. - person Steve Jessop; 20.01.2010
comment
Или другой пример: вы пишете класс, представляющий выражения в исчислении высказываний. Они не конвертируются в bool, но есть очевидные и продуктивные значения operator&& и operator||, каждый из которых возвращает объект того же типа. Конечно, они не замыкаются (что бы это вообще значило), но я сомневаюсь, что это вызовет путаницу. Как и в случае с большинством перегрузок операторов, в нем не так много всего, но я думаю, что Proposition C = A && B; читается немного лучше, чем Proposition C = and(A,B); или A.and(B);. - person Steve Jessop; 21.01.2010

Если не ошибаюсь, эта операция не определена. Присвоение переменной и последующее обращение к той же переменной в одном операторе не определено.

person slebetman    schedule 20.01.2010
comment
Здесь это хорошо определено. && вводит точку последовательности, поэтому alpha имеет определенное значение перед вторым тестом (конечно, после исправления приоритета оператора). - person Alok Singhal; 20.01.2010
comment
Проблема не в одном утверждении, а в отсутствии промежуточной точки последовательности. Помимо прочего, && действительно устанавливает точку последовательности, поэтому при правильном использовании он предотвращает проблему, о которой вы думаете. - person Jerry Coffin; 20.01.2010
comment
@Alok, Какого вы ожидаете от четко определенного значения альфы? Точка последовательности или нет, она все еще используется неинициализированной. - person Dan Olson; 20.01.2010
comment
@Dan: если value1 и value2 инициализированы, if ((alpha = value1 - value2) && (alpha > 0.001)) четко определен, а alpha не используется без инициализации. - person Alok Singhal; 20.01.2010
comment
Согласен, но вопрос не в этом. - person Dan Olson; 20.01.2010
comment
Присвоение переменной и последующее обращение к той же переменной в одном операторе совершенно четко определено. В противном случае у нас было бы a = a + 1 как undefined. Единственная важная вещь, на которую следует обратить внимание, - это то, что переменная должна быть прочитана с целью определения ее нового значения. - person AnT; 21.01.2010

Обычно я всегда использую круглые скобки, чтобы сделать мой код более понятным для моих целей.

person cquillen    schedule 20.01.2010

Он оценивается слева направо.

Однако в вашем случае назначение - это последнее, что должно произойти, и все они будут вести себя так (где альфа используется как часть расчета для получения результата для его инициализации):

if (int alpha = (value1-value2 && alpha > 0.001))

Вы не можете смешивать объявления переменных в сложных выражениях, поэтому следующее не будет компилироваться:

if ((int alpha = value1-value2) && (alpha > 0.001))

Поэтому вам нужно разделить его на две строки:

int alpha = value1 - value2;
if (alpha > 0.001)
person UncleBens    schedule 20.01.2010

if (int alpha = value1-value2 && alpha > 0.001)

Согласно правила будут оцениваться в следующем порядке:

1.  (value1-value2)   [evaluate subtraction]
2.  && (left side)    [test left side]
3.  (alpha > 0.001)   [evaluated only if value-value2 != 0]
4.  && (right side)   [test right side]
4.  alpha =           [assignment]

На шаге 3 сначала оценивается альфа. Поскольку он не был назначен - и, возможно, не объявлен, правила на этот счет не ясны - это вызывает ошибку.

Недостаток в том, что присваивание имеет более низкий приоритет, чем &&. Что еще не работает, но уже ближе:

if (int alpha = value1-value2, alpha > 0.001)

Gcc дает error: expected expression before ‘int’. Ну может не ближе. В исходном заявлении gcc говорит то же самое.

person wallyk    schedule 20.01.2010

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

Попробуй это.

int alpha;
if ((alpha=value1-value2) && alpha>0.001)

Но я не думаю, что это делает то, что вам нужно. У вас есть alpha как int, и вы затем сравниваете его со значением с плавающей запятой. Первая часть оператора && будет возвращать истину, пока альфа не равна нулю, а вторая часть вернет истину, если альфа больше 0. Так что вам, вероятно, следует сделать это.

int alpha;
if ((alpha=value1-value2)>0)

или для гораздо более читаемого кода

int alpha=value1-value2
if (alpha>0)

Но чтобы ответить на ваш исходный вопрос: && выполняется слева направо и замыкается, когда ответ очевиден. То есть, если первая часть && ложна, вторая даже не оценивается!

person miked    schedule 20.01.2010

Вот статья, список приоритетов и ассоциативности операторов.

Насколько я могу судить, ваше намерение состоит в том, чтобы объявить временное значение, присвоить ему значение value1-value2, затем проверить результат и ввести блок if, если он больше некоторого значения. alpha объявляется как int, но вы, похоже, сравниваете его с двойным. альфа должна быть двойной.

Вы творчески используете временные конструкции. Ясный часто лучше, чем милый. Вместо этого сделайте это:

double alpha = value1-value2;
if (alpha > 0.001)
person John Dibling    schedule 20.01.2010

Согласно: http://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B

- LtR
> LtR
&& LtR
= RtL

учитывая ваш пример

(int alpha = value1-value2 && alpha > 0.001)
(int alpha = (value1-value2) && alpha > 0.001)
(int alpha = (value1-value2) && (alpha > 0.001))
(int alpha = (value1-value2) && (alpha > 0.001))
(int alpha = ((value1-value2) && (alpha > 0.001)))
person XAder    schedule 20.01.2010
comment
= в этом случае не является оператором. Таким образом, использование таблицы приоритетов для = - совершенно бессмысленное занятие. - person AnT; 20.01.2010

Как написано, это выражение делает следующее:

  1. Вычисляет value1 - value2 и преобразует его в bool путем неявного сравнения с нулем, т. Е. Фактически (value1 - value2) != 0
  2. Оценивает alpha > 0.001 после усечения 0.001 до int(0). На этом этапе alpha не инициализирован.
  3. Вычисляет логическое И двух предыдущих оценок.
  4. Преобразует логический результат логического И обратно в целое число.

Я думаю, что это резюмирует остальные сообщения. Единственная причина, по которой я опубликовал отдельный ответ, состоит в том, что я не смог найти ни одного, в котором упоминалось бы, когда alpha не был инициализирован, и все преобразования, которые здесь происходят; ответ wallyk ближе всего.

Конечно, остальные ответы, в которых предлагается использовать круглые скобки и отдельное объявление alpha, - это именно то, что вы должны сделать, чтобы исправить это. Объявление переменных в операторе if является частью языка, для которого я не нашел хорошего применения - объявления в структурах повторения кажутся более подходящими.

person D.Shawley    schedule 20.01.2010

Проблема в том, что выражение оценивается так:

if (int alpha = (value1-value2 && alpha > 0.001))

Используйте круглые скобки, чтобы исправить левую и правую части оператора &&:

if ((int alpha = value1-value2) && (alpha > 0.001))

person Aaron    schedule 20.01.2010