"х = ++ х" действительно ли это не определено? - PullRequest
12 голосов
/ 01 сентября 2010

Я использую Coverity Prevent в проекте для поиска ошибок.

Сообщается об ошибке для этого выражения (Имена переменных, конечно, изменены):

x=
   (a>= b) ?
   ++x: 0;

Сообщение:

EVALUATION_ORDER дефект: В "x=(a>= b) ? ++x: 0;" "x" записано в "x" (присвоение LHS) и записано в "(a>= b) ? ++x: 0; "но порядок, в котором происходят побочные эффекты, не определен, поскольку нет промежуточной точки последовательности.КОНЕЦ СООБЩЕНИЯ

Хотя я могу понять, что "x = x++" не определено, это немного сложнее для меня.Это ложное срабатывание или нет?

Ответы [ 6 ]

28 голосов
/ 01 сентября 2010

Условный оператор ?: имеет точку последовательности между вычислением условия (первый операнд) и оценкой второго или третьего операнда, но у него нет выделенной точки последовательности после вычисления второго или третьего операнда , Это означает, что две модификации x в этом примере потенциально противоречивы (не разделены точкой последовательности). Итак, Coverity Prevent прав.

Ваше заявление на этот счет практически эквивалентно

a >= b ? x = ++x : x = 0;

с той же проблемой, что и в x = ++x.

Теперь заголовок вашего вопроса предполагает, что вы не знаете, является ли x = ++x неопределенным. Это действительно не определено. Не определено по той же причине x = x++ не определено. Короче говоря, если один и тот же объект изменяется более одного раза между парой смежных точек последовательности, поведение не определено. В этом случае x изменяется присваиванием и ++, и нет последовательности, чтобы "изолировать" эти модификации друг от друга. Итак, поведение не определено. В этом отношении нет абсолютно никакой разницы между ++x и x++.

12 голосов
/ 01 сентября 2010

Независимо от точности сообщения, замена рассматриваемого кода на x= (a>= b) ? x+1: 0; достигает той же цели без какой-либо путаницы.Если инструмент запутан, то, возможно, следующий человек, который будет смотреть на этот код, тоже будет.

Предполагается, что x не имеет перегруженного оператора приращения с побочными эффектами, на которые вы здесь полагаетесь.

8 голосов
/ 01 сентября 2010

Оператор x = ++x; записывает в переменную x дважды, прежде чем нажать точку последовательности , и, следовательно, поведение не определено.

3 голосов
/ 01 сентября 2010

Трудно представить компилятор, выдающий код для "x = ++ x;" который на самом деле не будет работать так же, как "++ x". Однако, если x не является энергозависимым, компилятору будет разрешено обрабатывать оператор "y = ++ x;" в

  y=x+1;
  x=x+1;

Утверждение "x = ++ x;" таким образом стал бы

  x=x+1;
  x=x+1;

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

Если переменная 'x' является изменчивой, я не могу представить себе какую-либо последовательность кода, в которой компилятор, который не пытался быть намеренно подлым, мог бы правомерно считать "x = x ++;" как имеющий какой-либо эффект, кроме чтения всех частей «x» ровно один раз и записи одинакового правильного значения во все части «x» ровно дважды.

0 голосов
/ 06 марта 2012

Чтобы понять это, вам нужно иметь базовое понимание точек последовательности.Смотрите эту ссылку: http://en.wikipedia.org/wiki/Sequence_point

Для оператора = точка последовательности отсутствует, поэтому нет гарантии, что значение x будет изменено до его повторного присвоения x.

0 голосов
/ 01 сентября 2010

Я полагаю, что логически, если вы напишите «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", программисты должны были бы знать и понимать правила. Без какой-либо очевидной выгоды это просто усложнит программы без всякой цели.

...