"х = ++ х" действительно ли это не определено?
Я использую Coverity Prevent в проекте, чтобы найти ошибки.
Он сообщает об ошибке для этого выражения (имена переменных, конечно, изменяются):
x=
(a>= b) ?
++x: 0;
Сообщение:
EVALUATION_ORDER дефект: In "
x=(a>= b) ? ++x: 0;
","x
"написано в"x
"(задание LHS) и написано в"(a>= b) ? ++x: 0;
"но порядок, в котором происходят побочные эффекты, не определен, потому что нет промежуточной точки последовательности. КОНЕЦ СООБЩЕНИЯ
Пока я могу это понятьx = x++
"не определено, это немного сложнее для меня. Является ли это ложным положительным или нет?
6 ответов
Условный оператор ?:
имеет точку последовательности между оценкой состояния (первый операнд) и оценкой второго или третьего операнда, но у него нет выделенной точки последовательности после оценки второго или третьего операнда. Это означает, что две модификации x
в этом примере потенциально конфликтующие (не разделенные точкой последовательности). Итак, Coverity Prevent - это правильно.
Ваше утверждение в этом отношении практически эквивалентно
a >= b ? x = ++x : x = 0;
с той же проблемой, что и в x = ++x
,
Теперь название вашего вопроса предполагает, что вы не знаете, x = ++x
не определено Это действительно не определено. По той же причине не определено x = x++
не определено Короче говоря, если один и тот же объект изменяется более одного раза между парой смежных точек последовательности, поведение не определено. В этом случае x
модифицируется назначением и ++
и нет последовательности, чтобы "изолировать" эти модификации друг от друга. Итак, поведение не определено. Там нет абсолютно никакой разницы между ++x
а также x++
в этой связи.
Независимо от точности сообщения, замена соответствующего кода на x= (a>= b) ? x+1: 0;
достигает той же цели без каких-либо путаницы. Если инструмент запутан, то, возможно, следующий человек, который будет смотреть на этот код, тоже будет.
Это предполагает, что x
не имеет перегруженного оператора приращения с побочными эффектами, на которые вы здесь полагаетесь.
Заявление x = ++x;
пишет в переменную x
дважды, прежде чем попасть в точку последовательности и, следовательно, поведение не определено.
Трудно представить компилятор, выдающий код для "x = ++x;" который на самом деле не будет работать так же, как "++ x". Однако, если x не является энергозависимым, компилятору будет разрешено обрабатывать оператор "y = ++x;" как
у = х +1; х = х +1;
Утверждение "x = ++x;" таким образом стал бы
х = х +1; х = х +1;
Если назначение одного арифметического выражения присваивания используется слишком быстро, так как операнд-источник для другого вызовет задержку конвейера, прежняя оптимизация может быть разумной. Очевидно, что это катастрофично, если приращенная и назначенная переменные - это одно и то же.
Если переменная 'x' является изменчивой, я не могу представить себе какую-либо последовательность кода, в которой компилятор, который не пытался быть намеренно подлым, мог бы правомерно считать "x = x ++;" как имеющий какой-либо эффект, кроме чтения всех частей "x" ровно один раз и записи одинакового правильного значения во все части "x" ровно дважды.
Я предполагаю, что логически, если вы напишите "x=++x" или "x=x++", в любом случае вы ожидаете, что конечный результат будет таким, что x на единицу больше, чем началось. Но сделайте это немного сложнее. Что если вы написали "x=x+(++x)"? Это то же самое, что "x=x+(x+1)"? Или мы сначала добавляем один, а затем добавляем x к себе, то есть "x=(x+1)+(x+1)"? Что если мы напишем "x=(x-)+(x++)"?
Даже если бы вы могли написать спецификацию языка, которая придавала бы однозначный смысл таким конструкциям, а затем могли бы реализовать ее чисто, зачем вам это нужно? Ввод одинакового приращения в присваивании одной и той же переменной просто не имеет смысла, и даже если мы вытеснили смысл из этого, он не предоставляет никакой полезной функциональности. Например, я уверен, что мы могли бы написать компилятор, который бы взял выражение типа "x+1=y-1" и выяснил, что это действительно означает "x=y-2", но зачем это беспокоить? Там нет выгоды.
Даже если бы мы написали компиляторы, которые делали что-то предсказуемое с "x = x ++ - ++ x", программисты должны были бы знать и понимать правила. Без какой-либо очевидной выгоды это просто усложнит программы без какой-либо цели.
Чтобы понять это, вы должны иметь базовое понимание точек последовательности. Смотрите эту ссылку: http://en.wikipedia.org/wiki/Sequence_point
Для оператора = точка последовательности отсутствует, поэтому нет гарантии, что значение x будет изменено до его повторного присвоения x.