В чем причина этого результата? - программирование
Подтвердить что ты не робот

В чем причина этого результата?

У меня есть следующий код.

    int x=80;
    int &y=x;
    x++;
    cout<<x<<" "<<--y;

Выход составляет 80 80. И я не понимаю, как это сделать. Я думал, что выход x будет 81, хотя я ничего не знаю о y. Как ссылочная переменная зависит от оператора декремента. Может кто-нибудь объяснить?

4b9b3361

Ответ 1

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

Когда вы пишете

std::cout << f() << g() << std::endl;

вывод покажет результат f(), а затем результат g(), но фактический вызов g() может произойти до вызова f().

Это даже хуже, чем это... это не то, что последовательность не предсказуема, но это действительно само понятие последовательности недействительно. В

std::cout << f(g()) << h(i()) << std::endl;

это, например, законно, что первая вызываемая функция - это g(), за которой следует i(), затем h() и, наконец, f(). Он даже не гарантировал, что порядок будет одинаковым для всех вызовов (не потому, что разработчикам компиляторов нравится высмеивать вас, а потому, что код может быть встроен, и компилятор может решить другой порядок, если содержащая функция встроена в другом контексте).

Единственными операторами С++, которые гарантируют последовательность в порядке оценки, являются:

  • &&: сначала оценивает левую сторону и только если результат "истина" оценивает правую сторону.
  • ||: сначала оценивает левую сторону, и только если результат "false" оценивает правую сторону.
  • ?:: сначала оценивает условие, а затем только второй или третий операнд
  • ,: оператор запятой... оценивает левую сторону, отбрасывает значение и затем оценивает и возвращает правую сторону. ПРИМЕЧАНИЕ: запятые между функциональными параметрами НЕ являются операциями запятой и не налагается порядок оценки.

Кроме того, этот guaratee действителен только для предопределенных операторов. Если вы перегружаете &&, || или , в своем классе, они просто нормальные операторы без каких-либо специальных ограничений на порядок оценки.

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

Ответ 2

Выражение оценивается как:

((cout << x) << " ") << --y;

Нет никакой точки последовательности (или упорядочения) между оценкой левой стороны и правой частью выражения, компилятор может вывести код, который оценивает --y как первый шаг.

Так как y является ссылкой на x здесь, это на самом деле поведение undefined, так как вы оба читаете и записываете в x в том же выражении без промежуточных точек последовательности.

Ответ 3

Это поведение undefined, стандарты C/С++ не определяют способ ввода аргумента в стек, и обычно аргумент переносится в обратном порядке, например здесь:

func(1, 2)

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

push 2
push 1
call func

поэтому в вашем случае --y оценивается и помещается до x. В этом примере ясно:

#include <iostream>

int a() { std::cout << "a" << std::endl ; return 1; }
int b() { std::cout << "b" << std::endl ; return 2; }

int main(void) {

    std::cout << a() << " " << b() << std::endl;

    return 0;
}

с первого взгляда, он должен печатать:

a
b
1 2

но он печатает:

b
a
1 2

Ответ 4

x++

увеличивает x и производит в качестве результата выражения исходное значение x.

В частности, для x ++ не существует временного упорядочения, подразумеваемого для приращения и создания исходного значения x. Компилятор может испускать машинный код, который производит исходное значение x, например. он может присутствовать в каком-то регистре и задерживает приращение до конца выражения (следующая точка последовательности). Хотя t x++, кажется, увеличивает x до 81, он не делает этого до печати. В соответствии с --y он получает добавочное значение (81) и уменьшает его до его печати, поскольку это оператор префикс.