Здравствуйте, Areg, Вы писали:
A>0 или 1 в зависимости в каком порядке компилятор вычислит арифметические выражения х=0 и х++.
мдя... както Joel Spolsky в одной из своих статей сказал что программисты не понимают принципы и работу с указателями в C... оказывается все намного сложнее
В приводимой ниже таблице сведены правила старшинства и ас-
социативности всех операций, включая и те, которые мы еще не
обсуждали. Операции, расположенные в одной строке, имеют
один и тот же уровень старшинства; строки расположены в по-
рядке убывания старшинства. Так, например, операции *, / и %
имеют одинаковый уровень старшинства, который выше, чем уро-
вень операций + и -.
OPERATOR ASSOCIATIVITY
++ RIGHT TO LEFT
|| LEFT TO RIGHT
= RIGHT TO LEFT
т.е. в начале будет вычислен x++, потом 0 || 0, и уже потом x = ...
Здравствуйте, _wind_, Вы писали:
__>Здравствуйте, _wind_, Вы писали:
__>проверил. Выдаёт 0. __>почему x++ не увеличивает значение икса? __>Если первый операнд оператора || есть false, то должен выполниться и второй опреанд!
А вот и неправда Как раз если первый операнд false, то второй уже не обрабатывается. Это вам не VB!
Здравствуйте, Oyster, Вы писали:
O>Здравствуйте, _wind_, Вы писали:
__>>Здравствуйте, _wind_, Вы писали:
__>>проверил. Выдаёт 0. __>>почему x++ не увеличивает значение икса? __>>Если первый операнд оператора || есть false, то должен выполниться и второй опреанд!
O>А вот и неправда Как раз если первый операнд false, то второй уже не обрабатывается. Это вам не VB!
Здравствуйте, Oyster, Вы писали:
O>Здравствуйте, _wind_, Вы писали:
__>>Здравствуйте, _wind_, Вы писали:
__>>проверил. Выдаёт 0. __>>почему x++ не увеличивает значение икса? __>>Если первый операнд оператора || есть false, то должен выполниться и второй опреанд!
O>А вот и неправда Как раз если первый операнд false, то второй уже не обрабатывается. Это вам не VB!
Как раз потому что первый операнд false будет выполнен второй операнд. Вот если бы первый был true, тогда другое дело...
Здравствуйте, woody, Вы писали:
FAD>>Неопределенное поведение, не стоит гадать на кофейной гуще.
W>В таком случае нужно курить спеки и приоритеты операций. Там обычно это все есть
Тут дело не в приоритете операций. Как уже сказали Tan4ik и hemmul, скобки будут расставлены однозначным образом.
(bool)(x = (0 || x++))
И, очевидно, есть одна точка следования между вычислением 0 и вычислением x++ — это фича оператора ||.
Но есть ли точка следования между x++ и x = (...) — тайна сия велика. Похоже, что нет.
Дальше — компилятор волен делать что попало, в зависимости от опций, а то и от погоды на луне (у него может просто сорвать башню на таких конструкциях).
Наиболее ожидаемые ответы — это 0 или 1 1.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, woody, Вы писали:
FAD>>>Неопределенное поведение, не стоит гадать на кофейной гуще.
W>>В таком случае нужно курить спеки и приоритеты операций. Там обычно это все есть
К>Тут дело не в приоритете операций. Как уже сказали Tan4ik и hemmul, скобки будут расставлены однозначным образом. К>
К>(bool)(x = (0 || x++))
К>
К>И, очевидно, есть одна точка следования между вычислением 0 и вычислением x++ — это фича оператора ||. К>Но есть ли точка следования между x++ и x = (...) — тайна сия велика. Похоже, что нет. К>Дальше — компилятор волен делать что попало, в зависимости от опций, а то и от погоды на луне (у него может просто сорвать башню на таких конструкциях). К>Наиболее ожидаемые ответы — это 0 или 1 1.
А>#include <stdio.h>
А>void main()
А>{
А> int x = 0;
А> if (x = 0 || x++)
А> printf("%d\n", x);
А> printf("%d\n", x);
А>}
А>
А>что выдаст и почему?
А>
Выдаст 0, потому что:
if (x = 0 || x++) эквивалентно if ((x = 0) || (x++))
операторы выполняются последовательно,
первым выполняется (x = 0), что есть false,
если первый оператор false, то выполняется второй оператор.
Так как это постинкремент, то сначала возвращается x (т.е. 0).
Условие не выполняется и инкремент не выполняется. Что и следовало доказать
Здравствуйте, CkuB, Вы писали:
А>>Именно такой код: А>>
А>>#include <stdio.h>
А>>void main()
А>>{
А>> int x = 0;
А>> if (x = 0 || x++)
А>> printf("%d\n", x);
А>> printf("%d\n", x);
А>>}
А>>
А>>что выдаст и почему?
А>>
CB>Выдаст 0, потому что: CB> if (x = 0 || x++) эквивалентно if ((x = 0) || (x++)) CB>операторы выполняются последовательно, CB>первым выполняется (x = 0), что есть false, CB>если первый оператор false, то выполняется второй оператор. CB>Так как это постинкремент, то сначала возвращается x (т.е. 0). CB>Условие не выполняется и инкремент не выполняется. Что и следовало доказать
Как уже было сказано выше, код приводит к неопределенному поведению. Не существует никакого определенного ответа на поставленный вопрос с точки зрения языков С/С++. Может напечататься все, что угодно. Может вообще ничего не напечататься.
С практической точки зрения, если забыть про неопределенное поведение, никто не гарантирует, что постинкретмент 'x' будет произведен до присваивания 'x' нового значения. Если постинкремент будет произведен после присвивания, то финальное знечение 'x' будет '1'. Если до — то '0'. Финальный 'printf', может напечатать как '0', так и '1'.
Но это все гадание на кофейной гуще. Правильный ответ на копрос задачи: код порождает неопределенное поведение, поэтому ответа на вопрос о том, что он "выдаст" (и выдаст ли что-нибудь вообще), не существует.
Здравствуйте, Андрей Тарасевич, Вы писали:
Ш>>i = v[i++]; // the behavior is unspecified
АТ>Известная опечатка стандарта. Деложно было быть 'undefined'.
В общем-то, какая разница, что за un- там будет. К феерверку это может привести только на экзотических платформах, а для x86 компилятор просто нарожает какую-то непредсказуемую пачку из add, inc, mov.
При глубокой оптимизации он может вообще своим скудным умищем предсказать, по какой ветке и с какими значениями надо идти. И не факт, что предскажет правильно.
Здравствуйте, alex_e_, Вы писали:
Ш>>Из стандарта.
Ш>>i = v[i++]; // the behavior is unspecified
__>Просто любопытно, о каком стандарте идет речь?
ANSI/ISO стандарте языка С++.
__>В msdn например есть вот такое описание
__>var j, k; __>k = 2; __>j = k++; __>Here, j is assigned the value 2, as the increment occurs after the expression is evaluated.
Для данного частного случая приведенное в MSDN утверждение можно сичтать условно верным. Формально же и в общем случае данное утверждение не верно и правильно ситуацию с побочными эффектами не описывает. То, что к 'k' применен постникремент совсем не означает, что инкремент будет произведен после вычисления всего выражения. Постникремент означает только то, что результатом подвыражения 'k++' является исходное значение 'k'. Когда же именно произойдет постинкремент — не оговаривается. Данный код может быть странслирован также как
var temp = k;
k = k + 1;
j = temp;
и как
k = k + 1;
j = k - 1;
__>Я всегда так и считал, разве это не так, что
__>i = v[i++]; всеравно, что
__>i = v[i]; __>i++;
Нет. Если закрыть глаза на пеопределенное поведение, 'i = v[i++]' может быть странслировано и как
i = v[i];
i = i + 1;
и как
temp = i;
i = i + 1;
i = v[temp];
Результат, разумеется, получится разный.
__>Причем мне кажется, это справедливо для любого скольугодно сложного оператора.
Здравствуйте, alex_e_, Вы писали:
Ш>>Из стандарта.
Ш>>i = v[i++]; // the behavior is unspecified
__>Просто любопытно, о каком стандарте идет речь?
Стандарт C++.
__>В msdn например есть вот такое описание
__>var j, k; __>k = 2; __>j = k++; __>Here, j is assigned the value 2, as the increment occurs after the expression is evaluated.
Это описание не вполне адекватно.
Представь себе, что j и k размещены в регистрах R1 и R2 некоторого воображаемого процессора. Тогда обе операции можно было бы выполнить одновременно одной ассемблерной инструкцией
mov R1 , R2++
В общем случае, всю вычислительную работу между двумя точками следования следует представлять себе как происходящую параллельно. Соответственно, если при этом происходит конфликт записи -- результат не определён.
Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>С практической точки зрения, если забыть про неопределенное поведение, никто не гарантирует, что постинкретмент 'x' будет произведен до присваивания 'x' нового значения. Если постинкремент будет произведен после присвивания, то финальное знечение 'x' будет '1'. Если до — то '0'. Финальный 'printf', может напечатать как '0', так и '1'.
Если постинкремент реализован посредством преинкремента, то постинкретмент 'x' будет произведен до присваивания 'x' нового значения. И результат должен быть всегда 0 и никогда 1.