Рейтинг:
2
OriginalGriff
Это не одно и то же. c--
является постфиксным оператором, который изменяет c
после того, как он будет использован.
Вы должны быть очень осторожны при их использовании, так как результаты, которые вы получите, могут быть не такими, как вы ожидали. Видеть здесь: Почему x = ++x + x++ дает мне неправильный ответ?[^]
Цитата:
Большое вам спасибо! Я прочитал статью и нашел "приоритет и порядок оценки" из MSDN.
На данный момент приоритет операторов не отвечает на вопрос "почему"
например
int a = 5;
int b = 3;
int i = 10;
int x = (i++) + a * b;
логически (если мы согласны с приоритетом) я должен быть 11 (!) и x = 26, а не 25, потому что i++ помещается в скобки.
но оператор ++ все равно опускается в конечном счете, независимо от направления оценки
Нет, вы ошибаетесь.
int x = i++ + a * b;
Использует приращение post fix, которое гласит: "используйте текущее значение
i
а затем добавьте один к
i
"
Если вы напишете его длинной рукой, то получите вот это:
int i2 = i;
i += 1;
x = i2 + a * b;
который:
25 == 10 + 3 * 5;
Это
почему? смешивание операторов автоматического приращения и декремента в одном и том же выражении настолько чревато: нет универсальных правил, чтобы точно сказать, когда должно быть сделано приращение.
Подумайте об этом, предположив, что i равно 10
x = i++ + i;
Какова величина x?
20?
21?
22?
"Правильный" ответ-21, и я заканчиваю как 11.
int i2 = i;
i += 1;
x = i2 + i;
Но... он легко может быть равен 20, если строго оценивать его справа налево:
x = i + i;
i += 1;
po_saa
Привет!
поместите эти два выражения в c# и выполните их.
Результат будет равным
OriginalGriff
Результат в "d" будет таким же, в чем и весь смысл - но значения в "c" не будет!
Пост - декремент в середине выражения совершенно законен- и даже иногда желателен. Это имеет "побочный эффект", что c уменьшается, но это совершенно законно и будет работать.
Нет никакого предупреждения, потому что он делает то, что от него ожидают и для чего он предназначен!
po_saa
речь шла не о синтаксисе или понимании выполнения операции.
Я имел в виду следующее:
(посмотрите на журнал Solutions _2)
- послушайте, согласитесь, это ненормальная ситуация
int d = c--; / / "c--" находится в конце выражения. Я согласен, что когда выражение закрывается после этого, операция postdecrement работает так, как ожидалось, и в этом случае "d==c"
int d = c-- - b * a; //но в этом случае "c--" находится в середине выражения и, по-видимому, должен быть выполнен полностью, чтобы вернуть значение выражению, в котором он участвует
Вопрос заключается в доказательстве казни
OriginalGriff
Нет, ты не понимаешь. Это совершенно нормальная ситуация.
Операторы Pre - и post-fix могут использоваться для любого значения lvalue в любой точке выражения, они не фиксируются к "концу" выражения (особенно потому, что многие компиляторы оценивают выражения справа налево, а не слева направо, когда порядок не важен)
Не имеет значения, если вы не "думаете, что они должны" - они могут, как и любой другой унарный оператор. Или вы предполагаете, что "a * -b * c" также не должно быть разрешено? :смеяться:
И реальная проблема заключается в том, что это оператор "побочного эффекта", поэтому вы не должны писать сложные выражения, используя их. Но ничто не мешает вам сделать это (кроме того, что конечные результаты не определены во многих языках и могут измениться без предварительного уведомления).
po_saa
О! И это довольно интересно:
- особенно потому, что многие компиляторы оценивают выражения справа налево, а не слева направо, когда порядок не важен"
Я считаю, что этот ответ "почему" для меня!
Я этого не знал.
Спасибо!
OriginalGriff
Пожалуйста - это объясняется в ссылке, которую я вам дал. Найдите "приоритет и порядок оценки", и вы увидите его.
po_saa
Большое вам спасибо! Я прочитал статью и нашел "приоритет и порядок оценки" из MSDN.
На данный момент приоритет операторов не отвечает на вопрос "почему"
например
int a = 5;
int b = 3;
int i = 10;
int x = (i++) + a * b;
логически (если мы согласны с приоритетом) я должен быть 11 (!) и x = 26, а не 25, потому что i++ помещается в скобки.
но оператор ++ все равно в конечном итоге опускается (не опускается, конечно, а выполняется после выражения), независимо от направления вычисления
OriginalGriff
Ответ обновлен.
po_saa
&ГТ;&ГТ;нет, вы не правы
О, неужели?!
int x = i++ + a * b;
Ты не забыл про скобки?
Разве так не должно быть:
int x=(i++) + a * b;
по моему мнению в данном случае это было бы так:
i += 1;
x = i + a * b;
потому что скобки находятся в основном приоритете... ?
Может быть (и я уверен), вы правы, потому что я вижу, что в компиляторе C# x==25!
Но почему?!
OriginalGriff
Скобки не имеют значения - они влияют только на приоритет оператора, а не на порядок вычисления.
Помните: "только операторы последовательного вычисления (,), логического и (&&), логического или (||), условного выражения (?:) и вызова функции образуют точки последовательности и поэтому гарантируют определенный порядок вычисления для своих операндов."
Они действуют как точка последовательности только в скобках.
Подумайте об этом: 2 + 3-это то же самое, что 3 + 2, да? Это фундаментально для математики (и называется ассоциативностью, которую вы помните с детства).
Поэтому, когда вы пишете x = (y) + (z), компилятор может сначала вычислить (y) или (z), потому что это не имеет значения для результата сложения, пока y и z полностью вычисляются до сложения. То же самое касается и умножения!
Если вы пишете x = (y + z) + a, то вы говорите: "добавьте y и z, затем добавьте a, но компилятор может игнорировать скобки, потому что они ничего не меняют.
Если вы пишете x = func(y + z) + a, то скобки функции действуют как точка последовательности и говорят компилятору, что y, z и y + z должны быть полностью вычислены перед вызовом func, но даже это не имеет никаких проблем с оценкой "a" сначала (просто потому, что так кажется), потому что это "не влияет на результат"
Только очень немногие операторы устанавливают последовательность оценки: && и || потому что спецификация устанавливает закон: "левая сторона &&,||, и ? должно быть оценено перед правой стороной"
Этот закон не существует для+, -, * или /
Не путайте приоритет с порядком оценки, они не одно и то же (или даже не связаны!)
po_saa
Ага!
Я пытаюсь исследовать ILDasm и вижу, что компилятор полностью игнорирует скобки - списки полностью одинаковы с скобками или без них
"Если вы пишете x = func(y + z) + a, то скобки функции действуют как точка последовательности и говорят компилятору, что y, z и y + z должны быть полностью оценены перед вызовом func, но даже это не имеет никаких проблем с оценкой "a" сначала (просто потому, что так кажется), потому что это "не влияет на результат"
но если это так, то компилятор должен полностью(!) оценить func(I++) в первую очередь, а не остальную часть выражения.
Но очевидно, что это не так
OriginalGriff
Почему? Это не имеет никакого эффекта на результат.
Если funcA(...) + funcB(...) возвращает 123, то какая разница, что funcA возвращает 100, а funcB возвращает 23? Оператор сложения не заботится, потому что сложение ассоциативно, и его можно записать funcB(...) + funcA(...) и дать тот же результат.
And so it's up to the compiler to do exactly what is convenient for it - which may not be what you think. Worse, the optimization phase of release compilation can *change that order* because it can "see" common expressions that it will only work out once, or reorder the whole expression in order to keep everything in a limited set of machine registers. You have no control over that, and that's why if you want to do something that relies on evaluation order you have to break it into separate lines to force the compiler to consider sequence points. And that's why you have to be very careful with "side effect" operations (particularly in property getters) or things can get very confusing, very quickly.
Вы все еще путаете приоритет с порядком, и они все еще не одно и то же!
po_saa
-вы все еще путаете приоритет с порядком, и они все еще не одно и то же!
- Сомневаюсь...
Я думаю, что мы говорим о разных вещах.
I++ - это куча процедур (размещение в стеке, инкрементирование, добавление и т. д.) правильно?
"функциональные скобки действуют как точка последовательности и сообщают компилятору, что y, z и y + z должны быть полностью вычислены перед вызовом func"
Это означает, что все процедуры этой группы должны быть оценены, и стек должен быть восстановлен.
Так что ++ - это не эфемерная вещь, это процедура, которая должна вернуть результат (в данном случае)
int i = 10;
int x = (i++) +1;
как видите, никаких других "я" за скобками нет.
какой порядок или приоритет мы здесь обсуждаем?
OriginalGriff
Нет, это унарный оператор, который имеет побочный эффект.
вы можете думать о приращении до и после исправления как о функциях:
public static int PlusPlusPrefix(ref int x)
{
x += 1;
вернуться х;
}
public static int PlusPlusSuffix(ref int x)
{
int y = x;
x += 1;
возвращение г;
}
И вы можете увидеть, что они делают. (Но ... не полагайтесь на него, компилятор не должен относиться к нему так - и не все компиляторы делают это!)
po_saa
-нет, это унарный оператор, который имеет побочный эффект.
с точки зрения Илдазма это не так.
Так как же получается, что результат инкремента помещается в другое место стека?
... хм..
Я должен исследовать Ильдазм ++I...
Рейтинг:
2
lmoelleb
Поскольку вы заявляете о себе, вы используете постдекремент - таким образом, значение C будет меняться после он используется в вашем выражении.
Так
d=(c--)-(b*a);
идентичен тому, что:
d=c-b*a; c=c-1;
Как
d=(--c)-(b*a);
идентичен тому, что
c=c-1;d=c-b*a;
Это становится действительно забавным только тогда, когда у вас есть несколько из них, работающих с одной переменной в одном операторе. Забавно играть, но никогда не используется в производственном коде, так что лично я просто забыл, как это работает.
po_saa
Привет!
Объяснение этому вполне понятно.
Задавая свой вопрос, я имел в виду, что операция в данном случае не очевидна.
Это должен быть механизм предупреждения в c#, чтобы сделать его более очевидным
lmoelleb
Операция делает именно то, что эта операция делала в течение многих десятилетий на нескольких языках - так каким же именно должно быть предупреждение? Что-то вроде "Если вы не знаете, как работает эта операция, она может дать другой результат, чем вы ожидаете"... но это касается всего. :)
po_saa
послушайте, согласитесь, это ненормальная ситуация
int d = c--; / / "c--" находится в конце выражения. Я согласен, что когда выражение закрывается после этого, операция postdecrement работает так, как ожидалось.
int d = c-- - b * a; //но в этом случае "c--" находится в середине выражения и, по-видимому, должен быть выполнен, чтобы вернуть значение выражению, в котором он участвует
.Но все-таки.. Вы правы "эта операция проводилась в течение многих десятилетий на нескольких языках"
lmoelleb
Лично я предпочитаю избегать этого стиля, но я бы не зашел так далеко, чтобы сказать, что это ненормально, и что его следует избегать во всех случаях. Может быть, вы можете найти (или написать) анализатор кода, если предпочитаете избегать его? Таким образом, вы получите предупреждение.
po_saa
Видите ли, "лично я предпочитаю избегать стиля" - вот что я имел в виду.
lmoelleb
Я не считаю, что мое личное предпочтение является определением "нормального". :Д
Но, как уже упоминалось, если вы действительно хотите получить здесь предупреждение, это будет что - то для анализатора кода, а не для основного компилятора.
po_saa
ААА... давайте рассмотрим это так же, как обмен ударами