Я видел этот вопрос в тесте, в котором мы должны сообщить вывод следующего кода.
#include<stdio.h>
int main(){
int k = 0;
while(+(+k--)!=0)
k=k++;
printf("%d\n", k);
return 0;
}
Выход есть -1
. Я не уверен, почему это ответ, хотя.
Что означает выражение +(+k--)
в C?
k=k++
не определено, но не определено, потому что оно никогда не выполняется из-за запутанного состояния - я голосую за закрытие, как дубликат этого вопроса .Ответы:
[Для протокола, я отредактировал этот ответ довольно значительно, так как он был принят и проголосовал. Это все еще говорит в основном то же самое, все же.]
Этот код глубоко, возможно, намеренно, запутывает. Он содержит узко предотвращенный экземпляр ужасного неопределенного поведения . В принципе невозможно определить, был ли человек, который создал этот вопрос, очень, очень умным или очень, очень глупым. И «урок», который может принести этот код для изучения или опроса о вас, а именно, о том, что унарный оператор плюс мало что делает, - безусловно, не является достаточно важным, чтобы заслужить такого рода диверсионное неверное направление.
Есть два запутанных аспекта кода, странное условие:
и безумное заявление, которое оно контролирует:
Я собираюсь осветить вторую часть первой.
Если у вас есть такая переменная,
k
которую вы хотите увеличить на 1, C дает вам не один, не два, не три, а четыре различных способа сделать это:k = k + 1
k += 1
++k
k++
Несмотря на эту награду (или, возможно, из-за этого), некоторые программисты запутываются и выкашивают такие искажения, как
Если вы не можете понять, что это должно делать, не волнуйтесь: никто не может. Это выражение содержит две разные попытки изменить
k
значение (k =
часть иk++
часть), и поскольку в C нет правила, чтобы сказать, какая из попыток модификации "выиграет", такое выражение формально не определено , что означает не только то, что у него нет определенного значения, но вся программа, содержащая его, является подозрительной.Теперь, если вы посмотрите очень внимательно, вы увидите, что в этой конкретной программе строка на
k = k++
самом деле не выполняется, потому что (как мы увидим) условие управления изначально ложно, поэтому цикл выполняется 0 раз. , Поэтому эта конкретная программа не может фактически быть неопределенным - но это все-таки патологический заблуждение.Смотрите также эти канонические SO ответы на все вопросы, касающиеся неопределенного поведения такого рода.
Но вы не спросили о
k=k++
роли. Вы спрашивали о первой запутанной части,+(+k--)!=0
состоянии. Это выглядит странно, потому что это странно. Никто никогда не будет писать такой код в реальной программе. Так что нет смысла учиться понимать это. (Да, это правда, изучение границ системы может помочь вам узнать о ее тонкостях, но в моей книге есть довольно четкая грань между творческими, заставляющими думать исследованиями по сравнению с глупыми, оскорбительными исследованиями, и это выражение очень четко неправильная сторона этой линии.)Во всяком случае, давайте рассмотрим
+(+k--)!=0
. (И после этого давайте забудем все об этом.) Любое подобное выражение следует понимать изнутри. Я полагаю, вы знаете, чтоделает. Он принимает
k
текущее значение и «возвращает» его остальной части выражения, и он более или менее одновременно уменьшаетсяk
, то есть сохраняет количествоk-1
обратноk
.Но тогда что делает
+
? Это унарный плюс, а не бинарный плюс. Это как унарный минус. Вы знаете, что двоичный минус делает вычитание: выражениевычитает б из а. И вы знаете, что унарный минус отрицает вещи: выражение
дает вам минус. То, что
+
делает унарный , это ... в основном ничего.+a
дает вамa
значение, после изменения положительных значений на положительные и отрицательных значений на отрицательные. Итак, выражениедает вам все, что
k--
дал вам, то есть,k
старая ценность.Но мы еще не закончили, потому что у нас есть
Это просто берет то, что
+k--
дало тебе, и+
снова относится к нему одинарно . Так что это дает вам все, что+k--
дало вам, то, чтоk--
дало вам, что былоk
старой ценностью.Итак, в конце концов, состояние
делает то же самое, что и гораздо более обычное условие
Сделал бы. (Это также делает то же самое, что
while(+(+(+(+k--)))!=0)
могло бы сделать даже более сложное на вид условие . И эти скобки на самом деле не нужны; это также делает то же самое,while(+ + + +k--!=0)
что и сделал бы.)Даже выяснить, что такое «нормальное» состояние
делает это довольно сложно. В этом цикле происходит две вещи: поскольку цикл может выполняться несколько раз, мы собираемся:
k--
, чтобы сделать всеk
меньше и меньше, но иНо мы выполняем свою
k--
роль сразу же, прежде чем (или в процессе) решить, предпринять ли еще одно путешествие по циклу. И помните, чтоk--
«возвращает» старое значениеk
, прежде чем уменьшать его. В этой программе начальное значениеk
равно 0. Такk--
что "вернуть" старое значение 0, а затем обновитьk
до -1. Но остальная часть условия!= 0
- но, как мы только что видели, в первый раз, когда мы проверили условие, мы получили 0. Таким образом, мы не будем совершать никаких циклов, поэтому не будем пытаться выполнить проблемное утверждениеk=k++
на всех.Другими словами, в этом конкретном цикле, хотя я сказал, что «происходит что-то вроде двух вещей», оказывается, что вещь 1 происходит один раз, а вещь 2 - ноль раз.
В любом случае, я надеюсь, что теперь достаточно понятно, почему это плохое оправдание для программы приводит к выводу -1 в качестве окончательного значения
k
. Обычно я не люблю отвечать на вопросы викторины, подобные этим - это похоже на мошенничество - но в этом случае, поскольку я так громогласно не согласен со всем смыслом упражнения, я не возражаю.источник
На первый взгляд кажется, что этот код вызывает неопределенное поведение, однако это не так.
Сначала давайте правильно отформатируем код:
Итак, теперь мы можем видеть, что утверждение
k=k++;
находится внутри цикла.Теперь давайте проследим программу:
Когда условие цикла сначала оценивается,
k
имеет значение 0. Выражениеk--
имеет текущее значениеk
, равное 0, иk
уменьшается как побочный эффект. Таким образом, после этого утверждения значениеk
-1.Начало
+
в этом выражении не влияет на значение, поэтому+k--
оценивается в 0 и аналогично+(+k--)
оценивается в 0.Затем
!=
оператор оценивается. Так0!=0
как false, тело цикла не вводится . Если бы тело было введено, вы бы вызвали неопределенное поведение, потому чтоk=k++
и чтение, и записьk
без точки последовательности. Но петля не введена, поэтому нет UB.Наконец,
k
печатается значение -1.источник
if (x != NULL) *x = 42;
Это не определено когдаx == NULL
? Конечно, нет. Неопределенное поведение не происходит в частях кода, которые не выполняются. Слово « поведение» - это подсказка. Код, который не выполняется, не имеет поведения, неопределенного или иного.k=k++
качественно отличается от*x=42
. Последний четко определен, еслиx
является допустимым указателем, но первый не определен, несмотря ни на что. (Я признаю, что вы, возможно, правы, но, опять же, я не собираюсь спорить об этом, и я все больше обеспокоен тем, что нас мастерски контролировали.)Вот версия этого, которая показывает приоритет оператора:
Два унарных
+
оператора ничего не делают, поэтому это выражение в точности эквивалентноk--
. Человек, который написал это, скорее всего, пытался возиться с вашим разумом.источник