- 1
pp = pp++;
Нашли или выдавили из себя код, который нельзя назвать нормальным, на который без улыбки не взглянешь? Не торопитесь его удалять или рефакторить, — запостите его на говнокод.ру, посмеёмся вместе!
+89
pp = pp++;
Что хотел сказать автор?...
pp += pp++ + ++pp;
2
8
26
80
242
728
2186
6560
19682
59048
...
Эту бомбу тогда вычислили бы быстро ><
pp = pp;
pp++;
бред.
не знаю как плюсах
смахивает на UB
C# даёт 10 :)
причем тут
{pp++;
pp = pp;
}
pp = pp++; // в яве, шарпе, js точно будет pp
а вот в c/c++ это как компилер решит, думаю т.к. под pp заведется одна ячейка, то результатом будет pp+1, но вообще хз
gcc/o1 тоже даёт 10.
по мне так как-то глупо. им там чо, компиляторы в лом делать?
>>>по мне так как-то глупо
а как по мне нормально,
интересно как оно на MS VC++ (там вроде 11 должно быть)
и в похапе (там вроде 10)?
кстати зачем херню редактировать - пусть бы все лулзы ловили, стыдно стало?
а потом еще "че вы меня минусуете?"
i=++i;
что
i=i++;
будет i )))
и в раби кажись тоже ))
нет, я нашёл ответ на свои вопросы.
всё равно мне непонятна логика компиляторостроителей. наверное, этот прикол упирается глубоко в древность, когда в компиляторах экономили на всём. вписать пару строчек - чтобы поведение было более интуитивным ("p = p++;" == "p = p; p++;") - раз плюнуть.
а тут, получается, код зависит от поведения стека нижлежащей платформы. дёшево, ламерски.
Объясню развернуто
Но на самом деле все компилеры (пока не знаю о MS VC++) подчиняются строгой логике и стандартам.
для инкремента создается отдельная переменная (в отдельной ячейке памяти или регистре), согласно приоритету операций т.к. это постинкремент сначала выполняется присваивание.
i=i
после этого выполняется инкремент отдельно созданной переменной
убедится в этом можно даже прочитав тот кусок IL-asma, который вы запостили выше
если у нас выражение
i=++i; то инкремент выполняется ДО, это не то что логично, а понятно даже кэпу
я уверен что на языках использующих виртуальные машины это будет так, насчет похапе хз, я его не так хорошо знаю, но т.к. он не низкоуровневый, то думаю, логика в нем такая же, питон и раби интерпретируют i++ как i+0+0, то есть i.
но вот низкоуровневые c/c++ могут иметь хитрые оптимизаторы и сейвануть оба i в один регистр, тогда получаем i+1, думаю gcc на при некоторых выставленых оптимизациях может именно так поступить, а MS вроде так и поступает, именно по этому я не уверен как оно будет работать.
и я знаю, как там внутри происходит в стеке.
однако, стек - это низкоуровневая вещь, и высокоуровневые языки от неё зависеть, имхо, не должны. я вообще об этом задумываться не должен.
лично мне кажется более интутинивным учитывать здесь инкремент, а не игнорировать его - не знаю как кажется другим.
так вот, учесть "интуитивность" здесь не так сложно - небольшое правило для анализатора, чтобы развернул выражение несколько иначе.
так никто не делает, не потому что они ламера, а потому что это мало кому нужно, ибо "p = p++" само по себе бессмысленно и/или говнокод.
Если интуитивно, то нормальный компилятор должен выдать ошибку и ткнуть носом.
если розетку лизнуть - определено, что будет )
Извиняюсь, что влезаю тут со своим похапе, но в нём всё очень даже определено...
http://www.php.net/manual/en/language.operators.precedence.php
Что выше, то и вычисляется в первую очередь. И смысл выражения из этого очень даже понятен. Постинкремент вычисляется первым, увеличивает значение переменной, но возвращает старое. Это старое поступает на оператор присваивания, который затирает увеличенное значение, заменяя его обратно на старое. Логика есть, её просто надо включить. Что касается интуитивности - разве разработчики компиляторов не в своём праве, если хотят отойти от неё в пользу строгой логичности выполнения? Разве не присутствует в этом решении такой плюс, как отсутствие необходимости разжёвывать это интуитивное исключение в мануале и терпеть толпу ламеров, которые про него не прочитают и споткнутся? Всякая интуитивность вроде предлагаемого исключения на конкретную узкую ситуацию - это костыль, а костыли в стратегическом плане ничего, кроме проблем, обычно не приносят. Это я в том числе как похапешник говорю. Т_Т
> но возвращает старое
> Логика есть
где здесь логика, которую я должен включить? на уровне языка здесь логики нет. на уровне реализации типа стека - может быть, только тогда я не секу pointa использования таких "высокоуровневых" языков. "p++" это ведь не (p + 1), операция должна писать прямо в переменную (и без разницы, когда это случается), при чём тут стек.
По-моему, кто-то не выучил матчасть.
> операция должна писать прямо в переменную (и без разницы, когда это случается)
> чтобы ++ случался уже после всего, а не где-то между стеком и жопой.
Операция присваивания - такая же часть выражения, как и любая другая, и момент её выполнения (как и любой другой, опять же) строго определён приоритетом операций. Этого совершенно достаточно для понимания, как вычисляется то или иное выражение. Другое дело, что в разных языках то ли таблица приоритетов немного разная, то ли компиляторы бажные и через пень-колоду следуют ей при обработке операций, которые мы тут мусолим.
Результат в C# 21, в gcc 22. При перестановке слагаемых в обоих 22.
Результат в C# 21, в gcc 22.
Результат в C# 23, в gcc 24.
В других компиляторах мне и проверять страшно. Результат в C# 20, в gcc 21. При перестановке слагаемых в обоих 21.
Результат в C# 19
Результат в C# 21
В gcc оба варианта 20.
Замена постинкремента и постдекремента на преинкремент и предекремент в данном примере не меняет результат.
>>>Результат в C# 23, в gcc 24.
а я о чем во второй посте говорил??
а вы MS VC++, его попробуйте ))
UPD. проверил в Мозилле, Хроме, Опере, ИЕ.
везде результат идентичный шарпу и яве
i=0;
(++i + ++i + ++i)
а то у меня по рукой ниче нету чтоб проверить
i
что впрочем логично
я знал, я знал, что какой-то из MS VC++ компилит так.
все у них не как у людей
Зря что ли autoconf генерирует короткие программы для теста компиляторов?
у тебя какое-то потакание говнокоду, я посмотрю (
i=0;
(++i + ++i + ++i)
GCC 4.34 -o1 = 7 какого?????
javascript: i=0;alert((++i + ++i + ++i)); = 6
Java, С# тоже должны 6
а вот MS 2005 по идее должен выдать 9 )))))
C# возвращает 6 (и javascript тоже).
>>> gcc выдаёт 7
кто возьмется объснить?
эта на MS VC++ 2005 испробуйте (++i + ++i + ++i)
На время публикации посмотрите. Почти одновременно. Я не сразу «Отправить» нажал.
Девятка из-за тройного преинкремента и оптимизации 3*i ?
Кстати, gcc -O2 тупо возвращает константу в ответе, то есть вычисления ещё на стадии компиляции. А без оптимизации генерирует истинный говнокод (синтаксис Intel мне более понятен, чем AT&T):
Итак, в сумме первые два слагаемых - это результат двух инкрементов i (оптимизация, блин), а третье слагаемое — после третьего инкремента.
бывает и такое ))
>>>то есть вычисления ещё на стадии компиляции.
причем неверные xD
из дизассемблинга ясно почему gcc неверно считает (выдает на 1 больший резулт)
(++i + ++i )=4
(++i + ++i + ++i )=7
(++i + ++i + ++i + ++i )=11
итд
оно создает копию первого ++i в eax позже чем надо (как уже сказано это надо делать 2-мя строками ранее), а с остальными работает нормально
походу баг
А ещё попробовать разбавить формулу другими выражениями, чтобы оптимизация споткнулась.
или ему 2-х регистров мало?
так и на этапе компиляции неправильно считает.
может это фича gcc? /-:
gcc генерирует код в два этапа. Если я правильно понял, что там написано в документации, то сначала генерируется код на языке RTL (register translation language) под виртуальный процессор, у которого количество и назначение регистров отличается от реального. Потом gcc конвертирует RTL в ассемблерный код для конкретного процессора. Даже если нам регистров хватает, их может не хватить RTL, поскольку он эмулирует весьма искусственную машину.
Если на сайте есть компиляторостроители, поправьте меня.
Все инкременты вычисляются ДО вычисления формулы.
и тут выдает 9.
он сейвит все i в одну переменную.
впрочем я говорил об этом еще в начале треда.
>>>Borland C возвращает (сюрприз!) 6, как в яве и в шарпе.
хм, а я его всегда говном считал
Отвлёкся от темы. Результат Борланда, совпадающий с явой и шарпом, меня тоже удивил.
(i++ + i++ + i++)
В gcc получается ноль, потому что он сначала складывает, потом выполняет инкремент (то есть i=3, а правая часть нулю).
MSVC на этот раз совпадает с шарпом: тройка в ответе. Листинг MSVC:
На этот раз всё чётко. Разный приоритет операций. gcc выполняет постинкремент после вычисления формулы, а шарп и MSVC — по ходу вычисления.
Watcom C возвращает 7, как и gcc.
Borland C возвращает (сюрприз!) 6, как в яве и в шарпе.
В обоих случаях 16-битный и 32-битный компиляторы вычисляют одинаково.
то есть все зависит от условленого порядка операций и в этом ничего сложного нет
кстати ява будет себя вести точно как и шарп и тому есть веские причины
в яве и шарпе приоритеты ++ и сложения одинаковы в c/c++
у инкремента выше
вот к примеру
pp = 10; pp = pp + pp++;
потому pp=10 + 10, а потом уже инкремент
при перестановке сначала инкремент (возвратит 10), потом сложение с уже увеличенным до 11
то есть
pp=10+11
>>>pp = 10; pp = pp + ++pp;
10+11 //т.к. прединкремент
++pp+pp
11+11 //т.к. прединкремент уже изменил значение ячейки
p = ++pp + ++pp;// тут вообще элементарно
11+12
в gcc как я понимаю более приоритетные инкременты
потому
>>pp = pp + pp++;
сначала выполнится инкремент, но возвратит 10, но pp уже изменилось а потом выполнит сложение
11 + 10, от перестановки сумма не меняется, поскольку инкремент выполняется раньше
>>>pp = pp + ++pp;
тут приоритет ++pp выше и он сразу увеличит значение pp на 1 и вернет 11
а потом сложение
11+11=22
итд...
>>А в javascript ещё веселее.
ЗЫ по поводу js я всегда думал он работает как ява и шарп, надо будет глянуть мануал
1) Автор Паскалист
2) рр это объект класса и ++ перегружен на выполнение какого-нибудь извращенского действия
inc(i) - без побочных эффектов???
>Си иногда называют write-only языком
У вас галлюцинации... Такое говорили про форт, причем исключительно неасиляторы.
эммм, какая разница, процедура это или функция. если изменяется состояние после вызова - то это побочный эффект. inc только и делает, что побочный эффект генерирует.
вот например процедура без побочного эффекта:
void f() { }
:)
по сути процедура это та же функция, только возвращающая "ничто".
Предлагаю всех, кто использует инкременты, декременты и присвоения в правой части, жечь на костре.
Дотошное понимание такой хрени нисколько не характеризует программиста :)
ну надо хотя бы иметь представление как будет выполнятся твой код
потому тот язык на котором пишешь необходимо знать как можно дотошнее.
[QUOTE] Я понял, что в программировании понимаю чуть меньше, чем нихрена.[/QUOTE]
чем больше знаний, тем больше понимаешь насколько их мало
[PHP]phphph[/PHP]
"p = p++" это бессмысленный говнокод. Зачем его понимать?
и тут нужно четко знать что произойдет.
а как вам такое? ))
И зло в том, что
1) это побочный эффект,
2) это побочный эффект с недетерминированным временем срабатывания
3) это экономит небольшое количество байтов в тексте программы, из-за чего их всё любят несмотря на первые 2 причины.
Наверное 3-й пункт есть проявление Великой Лени выражающейся в стремлении печатать как можно меньше букв.
Выражение pp += 1 вполне может заменить всё, где могут понадобиться пре/постинкременты. Классический пример с
while(*p++=*q++);
можно переписать как
while(*p = *q) { p += 1; q += 1; }
что не столь изящно, но намного чётче сформулировано.
Special cases are not special enough
++ - конкатенация списков
весь батхёрт из пустого места - в write-only языке, из исторических причин, или в угоду ленивым разработчикам оптимизаторов, просто зафиксировали, что это UB использовать *инкремент рядом с доступом к переменной - развлекайтесь, как хотите, дети мои, а в read-write-execute-profit языках изначально отделили мух от котлет, рассказав в каком конкретно направлении и порядке какие операции выполняются
эволюция-с
Инкременты же сахарок. Для экономии одного символа.
>и считаю, что она должна быть стейтментом
Главное - убрать побочный эффект, да.
Убрать и не пущать, ибо не стоит оно того гемора и майндфака.