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