- 1
pp = pp++;
Нашли или выдавили из себя код, который нельзя назвать нормальным, на который без улыбки не взглянешь? Не торопитесь его удалять или рефакторить, — запостите его на говнокод.ру, посмеёмся вместе!
+89
pp = pp++;
Что хотел сказать автор?...
3.14159265 22.06.2010 12:18 # 0
3.14159265 22.06.2010 12:24 # 0
pp += pp++ + ++pp;
tinynick 22.06.2010 12:37 # 0
2
8
26
80
242
728
2186
6560
19682
59048
...
Эту бомбу тогда вычислили бы быстро ><
Мистер Хэнки 22.06.2010 12:33 # 0
Webkill 22.06.2010 12:57 # −7
pp = pp;
pp++;
бред.
3.14159265 22.06.2010 13:00 # 0
не знаю как плюсах
смахивает на UB
Webkill 22.06.2010 13:11 # −5
C# даёт 10 :)
3.14159265 22.06.2010 13:20 # −2
причем тут
{pp++;
pp = pp;
}
pp = pp++; // в яве, шарпе, js точно будет pp
а вот в c/c++ это как компилер решит, думаю т.к. под pp заведется одна ячейка, то результатом будет pp+1, но вообще хз
Webkill 22.06.2010 13:24 # −6
gcc/o1 тоже даёт 10.
по мне так как-то глупо. им там чо, компиляторы в лом делать?
3.14159265 22.06.2010 13:44 # 0
>>>по мне так как-то глупо
а как по мне нормально,
интересно как оно на MS VC++ (там вроде 11 должно быть)
и в похапе (там вроде 10)?
кстати зачем херню редактировать - пусть бы все лулзы ловили, стыдно стало?
а потом еще "че вы меня минусуете?"
3.14159265 22.06.2010 14:06 # −1
i=++i;
что
i=i++;
будет i )))
и в раби кажись тоже ))
paranoid 23.06.2010 14:14 # 0
telnet 22.06.2010 14:23 # 0
Webkill 22.06.2010 15:35 # −7
нет, я нашёл ответ на свои вопросы.
всё равно мне непонятна логика компиляторостроителей. наверное, этот прикол упирается глубоко в древность, когда в компиляторах экономили на всём. вписать пару строчек - чтобы поведение было более интуитивным ("p = p++;" == "p = p; p++;") - раз плюнуть.
а тут, получается, код зависит от поведения стека нижлежащей платформы. дёшево, ламерски.
3.14159265 22.06.2010 17:09 # +2
Объясню развернуто
Но на самом деле все компилеры (пока не знаю о MS VC++) подчиняются строгой логике и стандартам.
для инкремента создается отдельная переменная (в отдельной ячейке памяти или регистре), согласно приоритету операций т.к. это постинкремент сначала выполняется присваивание.
i=i
после этого выполняется инкремент отдельно созданной переменной
убедится в этом можно даже прочитав тот кусок IL-asma, который вы запостили выше
если у нас выражение
i=++i; то инкремент выполняется ДО, это не то что логично, а понятно даже кэпу
я уверен что на языках использующих виртуальные машины это будет так, насчет похапе хз, я его не так хорошо знаю, но т.к. он не низкоуровневый, то думаю, логика в нем такая же, питон и раби интерпретируют i++ как i+0+0, то есть i.
но вот низкоуровневые c/c++ могут иметь хитрые оптимизаторы и сейвануть оба i в один регистр, тогда получаем i+1, думаю gcc на при некоторых выставленых оптимизациях может именно так поступить, а MS вроде так и поступает, именно по этому я не уверен как оно будет работать.
Webkill 22.06.2010 18:40 # −7
и я знаю, как там внутри происходит в стеке.
однако, стек - это низкоуровневая вещь, и высокоуровневые языки от неё зависеть, имхо, не должны. я вообще об этом задумываться не должен.
лично мне кажется более интутинивным учитывать здесь инкремент, а не игнорировать его - не знаю как кажется другим.
так вот, учесть "интуитивность" здесь не так сложно - небольшое правило для анализатора, чтобы развернул выражение несколько иначе.
так никто не делает, не потому что они ламера, а потому что это мало кому нужно, ибо "p = p++" само по себе бессмысленно и/или говнокод.
babaika 22.06.2010 20:40 # +1
Если интуитивно, то нормальный компилятор должен выдать ошибку и ткнуть носом.
Webkill 22.06.2010 20:55 # −5
если розетку лизнуть - определено, что будет )
paranoid 23.06.2010 14:15 # +2
telnet 22.06.2010 21:49 # +1
Извиняюсь, что влезаю тут со своим похапе, но в нём всё очень даже определено...
http://www.php.net/manual/en/language.operators.precedence.php
Что выше, то и вычисляется в первую очередь. И смысл выражения из этого очень даже понятен. Постинкремент вычисляется первым, увеличивает значение переменной, но возвращает старое. Это старое поступает на оператор присваивания, который затирает увеличенное значение, заменяя его обратно на старое. Логика есть, её просто надо включить. Что касается интуитивности - разве разработчики компиляторов не в своём праве, если хотят отойти от неё в пользу строгой логичности выполнения? Разве не присутствует в этом решении такой плюс, как отсутствие необходимости разжёвывать это интуитивное исключение в мануале и терпеть толпу ламеров, которые про него не прочитают и споткнутся? Всякая интуитивность вроде предлагаемого исключения на конкретную узкую ситуацию - это костыль, а костыли в стратегическом плане ничего, кроме проблем, обычно не приносят. Это я в том числе как похапешник говорю. Т_Т
Webkill 22.06.2010 22:58 # −7
> но возвращает старое
> Логика есть
где здесь логика, которую я должен включить? на уровне языка здесь логики нет. на уровне реализации типа стека - может быть, только тогда я не секу pointa использования таких "высокоуровневых" языков. "p++" это ведь не (p + 1), операция должна писать прямо в переменную (и без разницы, когда это случается), при чём тут стек.
Webkill 22.06.2010 23:14 # −7
telnet 23.06.2010 06:54 # 0
По-моему, кто-то не выучил матчасть.
> операция должна писать прямо в переменную (и без разницы, когда это случается)
> чтобы ++ случался уже после всего, а не где-то между стеком и жопой.
Операция присваивания - такая же часть выражения, как и любая другая, и момент её выполнения (как и любой другой, опять же) строго определён приоритетом операций. Этого совершенно достаточно для понимания, как вычисляется то или иное выражение. Другое дело, что в разных языках то ли таблица приоритетов немного разная, то ли компиляторы бажные и через пень-колоду следуют ей при обработке операций, которые мы тут мусолим.
inkanus-gray 22.06.2010 23:25 # +3
Результат в C# 21, в gcc 22. При перестановке слагаемых в обоих 22.
Результат в C# 21, в gcc 22.
Результат в C# 23, в gcc 24.
В других компиляторах мне и проверять страшно. Результат в C# 20, в gcc 21. При перестановке слагаемых в обоих 21.
Webkill 22.06.2010 23:42 # −6
inkanus-gray 22.06.2010 23:46 # +2
inkanus-gray 22.06.2010 23:59 # +2
Результат в C# 19
Результат в C# 21
В gcc оба варианта 20.
Замена постинкремента и постдекремента на преинкремент и предекремент в данном примере не меняет результат.
Webkill 23.06.2010 00:03 # −7
inkanus-gray 23.06.2010 00:07 # +2
inkanus-gray 23.06.2010 00:13 # −1
telnet 23.06.2010 06:55 # +3
3.14159265 23.06.2010 09:14 # 0
>>>Результат в C# 23, в gcc 24.
а я о чем во второй посте говорил??
а вы MS VC++, его попробуйте ))
3.14159265 23.06.2010 17:20 # +1
3.14159265 23.06.2010 17:28 # +1
UPD. проверил в Мозилле, Хроме, Опере, ИЕ.
везде результат идентичный шарпу и яве
inkanus-gray 23.06.2010 18:32 # 0
3.14159265 24.06.2010 09:36 # 0
3.14159265 23.06.2010 10:15 # 0
i=0;
(++i + ++i + ++i)
а то у меня по рукой ниче нету чтоб проверить
3.14159265 23.06.2010 10:21 # 0
i
что впрочем логично
koodeer 23.06.2010 15:18 # +1
3.14159265 23.06.2010 16:46 # +1
я знал, я знал, что какой-то из MS VC++ компилит так.
все у них не как у людей
inkanus-gray 23.06.2010 17:05 # 0
Webkill 23.06.2010 18:12 # −4
inkanus-gray 23.06.2010 18:14 # 0
Webkill 23.06.2010 18:20 # −4
inkanus-gray 23.06.2010 18:35 # 0
Зря что ли autoconf генерирует короткие программы для теста компиляторов?
Webkill 23.06.2010 21:04 # −1
у тебя какое-то потакание говнокоду, я посмотрю (
3.14159265 23.06.2010 17:20 # +1
i=0;
(++i + ++i + ++i)
GCC 4.34 -o1 = 7 какого?????
javascript: i=0;alert((++i + ++i + ++i)); = 6
Java, С# тоже должны 6
а вот MS 2005 по идее должен выдать 9 )))))
inkanus-gray 23.06.2010 17:20 # 0
C# возвращает 6 (и javascript тоже).
3.14159265 23.06.2010 17:27 # +1
>>> gcc выдаёт 7
кто возьмется объснить?
эта на MS VC++ 2005 испробуйте (++i + ++i + ++i)
inkanus-gray 23.06.2010 17:59 # +2
На время публикации посмотрите. Почти одновременно. Я не сразу «Отправить» нажал.
Девятка из-за тройного преинкремента и оптимизации 3*i ?
Кстати, gcc -O2 тупо возвращает константу в ответе, то есть вычисления ещё на стадии компиляции. А без оптимизации генерирует истинный говнокод (синтаксис Intel мне более понятен, чем AT&T):
Итак, в сумме первые два слагаемых - это результат двух инкрементов i (оптимизация, блин), а третье слагаемое — после третьего инкремента.
inkanus-gray 23.06.2010 18:03 # +1
3.14159265 23.06.2010 18:14 # +1
бывает и такое ))
>>>то есть вычисления ещё на стадии компиляции.
причем неверные xD
из дизассемблинга ясно почему gcc неверно считает (выдает на 1 больший резулт)
(++i + ++i )=4
(++i + ++i + ++i )=7
(++i + ++i + ++i + ++i )=11
итд
оно создает копию первого ++i в eax позже чем надо (как уже сказано это надо делать 2-мя строками ранее), а с остальными работает нормально
походу баг
inkanus-gray 23.06.2010 18:17 # 0
А ещё попробовать разбавить формулу другими выражениями, чтобы оптимизация споткнулась.
3.14159265 23.06.2010 18:32 # +1
или ему 2-х регистров мало?
так и на этапе компиляции неправильно считает.
может это фича gcc? /-:
inkanus-gray 23.06.2010 18:41 # 0
inkanus-gray 23.06.2010 19:36 # 0
gcc генерирует код в два этапа. Если я правильно понял, что там написано в документации, то сначала генерируется код на языке RTL (register translation language) под виртуальный процессор, у которого количество и назначение регистров отличается от реального. Потом gcc конвертирует RTL в ассемблерный код для конкретного процессора. Даже если нам регистров хватает, их может не хватить RTL, поскольку он эмулирует весьма искусственную машину.
Если на сайте есть компиляторостроители, поправьте меня.
inkanus-gray 23.06.2010 20:02 # 0
inkanus-gray 23.06.2010 20:12 # +1
Все инкременты вычисляются ДО вычисления формулы.
3.14159265 24.06.2010 09:21 # 0
и тут выдает 9.
он сейвит все i в одну переменную.
впрочем я говорил об этом еще в начале треда.
>>>Borland C возвращает (сюрприз!) 6, как в яве и в шарпе.
хм, а я его всегда говном считал
inkanus-gray 24.06.2010 14:31 # 0
Отвлёкся от темы. Результат Борланда, совпадающий с явой и шарпом, меня тоже удивил.
inkanus-gray 23.06.2010 20:25 # 0
(i++ + i++ + i++)
В gcc получается ноль, потому что он сначала складывает, потом выполняет инкремент (то есть i=3, а правая часть нулю).
MSVC на этот раз совпадает с шарпом: тройка в ответе. Листинг MSVC:
На этот раз всё чётко. Разный приоритет операций. gcc выполняет постинкремент после вычисления формулы, а шарп и MSVC — по ходу вычисления.
This is obvious 23.06.2010 21:01 # +1
inkanus-gray 23.06.2010 21:23 # +2
inkanus-gray 23.06.2010 19:29 # 0
Watcom C возвращает 7, как и gcc.
Borland C возвращает (сюрприз!) 6, как в яве и в шарпе.
В обоих случаях 16-битный и 32-битный компиляторы вычисляют одинаково.
Webkill 23.06.2010 21:06 # −1
Stalker 23.06.2010 21:22 # +2
inkanus-gray 23.06.2010 21:23 # 0
3.14159265 23.06.2010 10:06 # +1
то есть все зависит от условленого порядка операций и в этом ничего сложного нет
кстати ява будет себя вести точно как и шарп и тому есть веские причины
в яве и шарпе приоритеты ++ и сложения одинаковы в 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 я всегда думал он работает как ява и шарп, надо будет глянуть мануал
inkanus-gray 23.06.2010 14:56 # +2
KoirN 23.06.2010 11:35 # +1
1) Автор Паскалист
2) рр это объект класса и ++ перегружен на выполнение какого-нибудь извращенского действия
3.14159265 23.06.2010 11:48 # +1
inkanus-gray 23.06.2010 14:53 # −1
Denis Popov 23.06.2010 15:08 # −3
inc(i) - без побочных эффектов???
>Си иногда называют write-only языком
У вас галлюцинации... Такое говорили про форт, причем исключительно неасиляторы.
inkanus-gray 23.06.2010 17:01 # −1
Webkill 23.06.2010 18:17 # −2
эммм, какая разница, процедура это или функция. если изменяется состояние после вызова - то это побочный эффект. inc только и делает, что побочный эффект генерирует.
вот например процедура без побочного эффекта:
void f() { }
:)
inkanus-gray 23.06.2010 18:21 # −2
Webkill 23.06.2010 18:22 # −3
по сути процедура это та же функция, только возвращающая "ничто".
inkanus-gray 23.06.2010 21:28 # +4
Предлагаю всех, кто использует инкременты, декременты и присвоения в правой части, жечь на костре.
Webkill 23.06.2010 22:18 # −4
Дотошное понимание такой хрени нисколько не характеризует программиста :)
3.14159265 24.06.2010 09:56 # +1
ну надо хотя бы иметь представление как будет выполнятся твой код
потому тот язык на котором пишешь необходимо знать как можно дотошнее.
[QUOTE] Я понял, что в программировании понимаю чуть меньше, чем нихрена.[/QUOTE]
чем больше знаний, тем больше понимаешь насколько их мало
3.14159265 24.06.2010 09:59 # 0
[PHP]phphph[/PHP]
3.14159265 24.06.2010 10:05 # −1
This is obvious 24.06.2010 11:41 # 0
Webkill 24.06.2010 11:05 # −3
"p = p++" это бессмысленный говнокод. Зачем его понимать?
3.14159265 24.06.2010 17:39 # +2
и тут нужно четко знать что произойдет.
3.14159265 24.06.2010 17:36 # 0
а как вам такое? ))
Lure Of Chaos 24.06.2010 18:04 # 0
Lure Of Chaos 23.06.2010 23:04 # +1
tinynick 24.06.2010 17:30 # +1
И зло в том, что
1) это побочный эффект,
2) это побочный эффект с недетерминированным временем срабатывания
3) это экономит небольшое количество байтов в тексте программы, из-за чего их всё любят несмотря на первые 2 причины.
Наверное 3-й пункт есть проявление Великой Лени выражающейся в стремлении печатать как можно меньше букв.
tinynick 24.06.2010 17:35 # +1
Выражение pp += 1 вполне может заменить всё, где могут понадобиться пре/постинкременты. Классический пример с
while(*p++=*q++);
можно переписать как
while(*p = *q) { p += 1; q += 1; }
что не столь изящно, но намного чётче сформулировано.
roman-kashitsyn 14.08.2012 17:21 # +1
bormand 14.08.2012 17:24 # 0
roman-kashitsyn 14.08.2012 17:27 # +3
Special cases are not special enough
++ - конкатенация списков
defecate-plusplus 14.08.2012 17:30 # +2
весь батхёрт из пустого места - в write-only языке, из исторических причин, или в угоду ленивым разработчикам оптимизаторов, просто зафиксировали, что это UB использовать *инкремент рядом с доступом к переменной - развлекайтесь, как хотите, дети мои, а в read-write-execute-profit языках изначально отделили мух от котлет, рассказав в каком конкретно направлении и порядке какие операции выполняются
эволюция-с
3.14159265 14.08.2012 18:17 # +1
Инкременты же сахарок. Для экономии одного символа.
>и считаю, что она должна быть стейтментом
Главное - убрать побочный эффект, да.
Убрать и не пущать, ибо не стоит оно того гемора и майндфака.
HaskellGovno 14.08.2012 17:32 # 0
3oJloToy_xyeLL 24.08.2021 21:26 # 0