2016-02-11 2 views
2

В отношении this вопрос.Имеет ли это выражение a = a + b - (b = a); дает неправильный вывод из-за точки последовательности в C++?

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

+7

Почему бы просто не поставить его на другую линию? Это облегчает чтение для программистов. Например. Я даже не знаю, чего ожидать в результате. – Caramiriel

+5

Это ужасное кодирование. Зачем вам это делать? –

+1

Это действительно плохой стиль кодирования. :-(* edit * другие были быстрее :) – HelloWorld

ответ

8

C++ 11 больше не имеет точек последовательности, но да, строка является неопределенным поведением, поскольку модификация b не упорядочена относительно ее чтения.

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

+1

Хороший ответ. Btw, [this] (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2239.html) документ подтверждает ваше заявление. – HelloWorld

+0

почему это 'a^= b, b^= a, a^= b;' не дает предупреждения о последовательности точек? – Lovely

+0

«Пара выражений, разделенных запятой, оценивается слева направо, ...» - N3337, 5.18 – Caramiriel

3

Да, насколько я могу судить, это неопределенное поведение. Точка с запятой здесь является единственной точкой последовательности, поэтому не определено, выполняется ли присвоение до или после использования той же самой переменной.

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

1

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

Скорее всего, вы пробовали это много раз, но вы использовали тот же самый компилятор, не так ли? В таком случае вам вряд ли удастся увидеть разные результаты. Для данного же кода кода компиляторы обычно создают стабильный результат.

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

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

assign b <- a 
a = a + b - a  // but now, B is already equal a 

или

assign temp1 <- a 
assign temp2 <- b 
assign b <- a 
a = temp1 + temp2 - a // here values are preserved 
1

Да, это неопределенное поведение и это даст следующее предупреждение

$ g ++ -Wall -o test test.cpp test.cpp: В функции 'int main()': test.cpp: 11: 21: предупреждение: операция на 'B' может быть определено [-Wsequence-точка]

0

Стандарт С (1999-е изд.) Говорит, что в разделе 6.5 пункта 2:

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

Так что, да, этот код нарушает правила точки последовательности (b читается, но не для определения нового значения b). C++ наследует это от C.

+0

Знаете ли вы, где говорится, что эти правила наследуются? – NathanOliver

+0

@NathanOliver Стандарт C++ с 2003 года имеет либо то же самое, либо очень похожее определение и обработку точек последовательности, и говорит то же, что и я, приведенный выше в разделе 5, раздел 4. –

+1

Вы правы в одной точке: C++ наследует от C и как это UB в C, вероятно, будет на C++. Но C и C++ теперь разные языки, и есть угловые случаи, когда они ведут себя по-разному. Поэтому использование C-стандарта, чтобы сказать, что выражение C++ недопустимо, явно недостаточно. Вам понадобится эталонная форма C++, явно заявляющая, что эта часть стандарта C должна соблюдаться в действительной программе на C++ (или непосредственно в транспозиции из стандарта C++) –

1

Если вы используете вышеуказанный «трюк» вместо стандартного swap, с Visual Studio, у вас будет неприятный сюрприз. Побочные эффекты оценок все еще здесь.

Смежные вопросы