Просмотры

Обсуждение:++i + ++i

Материал из Lurkmore

Перейти к: навигация, поиск
Legendary-thread.jpg Примечательные обсуждения
Политика и заговоры  Ватник ( 1 / 2 / 3 ) • Выборы ( 1 / 2 ) • ГЛОНАСС ( 1 ) • Закручивать гайкиКопираст ( 1 ) • Кописрач ( 1 ) • Лунный заговор ( 1 / 2 ) • Майдан ( 1 / 2 / 3 / 4 / 5 / 6 / 7 / 8 / 9 / 10 / 11 / 12 / 13 / 14 / 15 / 16 / 17 / 18 / 19 / 20 / 21 / 22 / 23 / 24 / 25 / 26 / 27 / 28 ) • Марш несогласныхНавальный ( 1 / 2 / 3 / 4 ) • ПолиткорректностьУкраина ( 1 / 2 / 3 / 4 )
Религия и мировоззрение  АгностицизмАтеизм ( 1 / 2 / 3 / 4 / 5 / 6 / 7 / 8 / 9 / 10 / 11 / 12 / 13 / 14 / 15 / 16 / 17 / 18 / 19 / 20 / 21 / 22 / 23 ) • ПГМ ( 1 / 2 / 3 / 4 / 5 / 6 ) • Православие ( 1 / 2 / 3 / 4 / 5 / 6 / 7 / 8 / 9 / 10 / 11 / 12 / 13 ) • Философия ( 1 )
Наука и образование  Великая Отечественная война ( 1 ) • Великая тайна воды ( 1 ) • Взлетит или не взлетит? ( 1 / 2 / 3 ) • ГСМ ( 1 / 2 ) • ЕГЭ ( 1 ) • Задача Льва Толстого ( 1 ) • Золотая медаль ( 1 ) • Курица или яйцо?Матановая капчаСтудент ( 1 ) • Плановое отключениеСистема ПоливановаЧернобыль ( 1 / 2 ) • Школьная иерархия ( 1 / 2 / 3 / 4 / 5 / 6 / 7 ) • ++i + ++i
Мораль и гуманизм  Анна БешноваВеганы ( 1 / 2 / 3 / 4 / 5 / 6 / 7 / 8 ) • Владимир ТурчинскийКошачье делоКраш-фетишМозг обезьяныПсиносрач ( 1 / 2 / 3 / 4 / 5 ) • Суп из младенцев
Эстетика и вкусы  Beon.ru ( 1 / 2 ) • Freedom FightersАртемий ТроицкийГарри ПоттерГовнарь ( 1 / 2 / 3 ) • КиберпанкЛинукс ( 1 / 2 / 3 ) • Обитаемый островПопса ( 1 ) • СериалТеория Большого ВзрываТёплый ламповый звук ( 1 / 2 )
Любовь и секс  Девственник ( 1 / 2 / 3 / 4 / 5 ) • Любовь ( 1 / 2 ) • Мужской шовинизм ( 1 / 2 / 3 / 4 / 5 / 6 / 7 ) • Пикапер ( 1 / 2 ) • Разведёнка с прицепом ( 1 / 2 / 3 / 4 / 5 / 6 ) • Тупая пизда ( 1 / 2 / 3 / 4 / 5 / 6 ) • Фурфаг ( 1 / 2 / 3 ) • Чайлдфри ( 1 / 2 )
Люди и персонажи  Cruel Addict ( 1 / 2 / 3 / 4 / 5 / 6 / 7 / 8 / 9 / 10 ) • Grovka ( 1 ) • Marina.netMr. Freeman ( 1 / 2 / 3 / 4 / 5 ) • RLHM ( 1 / 2 / 3 / 4 / 5 ) • Альберт Акчурин ( 1 ) • Айн Рэнд ( 1 / 2 ) • Владимир Высоцкий ( 1 ) • Волшебный кролик ( 1 ) • Денис Попов ( 1 ) • ДжипсилиляЖеня ДуховниковаЖiдомасонъ РабiновичъЗнаменитость российского уровня ( 1 ) • Михаил Задорнов ( 1 ) • OлегРезуноид ( 1 / 2 / 3 / 4 / 5 / 6 / 7 / 8 / 9 ) • Тали ( 1 ) • Фрейд ( 1 ) • Цой ( 1 )
Прочее  Avatar ( 1 / 2 / 3 / 4 / 5 / 6 / 7 / 8 ) • Fallout ( 1 / 2 / 3 / 4 / 5 ) • Lineage II ( 1 ) • Forex ( 1 / 2 / 3 ) • Touchmindfuck.jpgАбсурдопедияIPhone ( 1 ) • БрендБыдлодевайс ( 1 ) • ГолодоморДело Кати Гордон ( 1 ) • Детский лагерь ( 1 ) • Детский садЗелёные титизеныЛуркоёб ( 1 ) • ЛьвовНаруто ( 1 / 2 ) • Небыдло ( 1 / 2 ) • Нижний НовгородОдномудОфисный планктон ( 1 ) • ПешеходРулесрачСпортWorld of Tanks ( 1 / 2 / 3 / 4 / 5 / 6 / 7 / 8 / 9 / 10 / 11 / 12 / 13 / 14 / 15 / 16 / 17 / 18 / 19 / 20 )

Анонимус, так откуда берется 14?

Если первым делом производится 2 инкремента, то i = 7, а 7 + 7 = 14
Капитан Очевидность объясняет для всех Слоупоков, как С++ получает число 14. Как уже было сказано, компилятор не рассчитывает выражение слева направо (как делает Жаба и Шарп), а сначала считает инкременты:
I.png
Вот так-то!
Что-то я не догнал краями. Мне казалось, что ++i возвращает значение после инкремента. То есть первый инкремент возвращает 6.
да всё просто, компилер юзает одну ячейку памяти, как определено (те без самоуправства) и это ячейка i. если её инкрементирвать 2 раза то получится 7. 7+7 = 14.
Все он правильно сказал, конпилятор использует одну ячейку памяти и результат в нее же записывает (на уровне машинного кода), а добавь ты вторую для временного хранения - результат будет как под управлением интерпретатором(виртуалмашиной), типа явы. и дело не в приоритете ++ а в compile i linke

Ы. Вы мне лучше такой майндфак объясните:

  int i = 5; i = (++i) + (++i) + (++i);

GCC. На выходе - 22. ШО ЗА ЁБАНЫЙ ЖЕ Ж НАХУЙ?

а без скобков?
один хуй. кто нибудь, попробуйте с другим компилятором. Алсо, при 4 повторах даёт 31(7+7+8+9, очевидно)
Тогда сдаюсь. В идеале, использование скобок должно изменять поведение, потому что обязывает вычислять.Я нуб.
((++i) + (++i)) + (++i) => ( (5+1=6->7) + (6+1=7))+ (7+1=8)=(7+7)+8 - т.е. сводим к двухместным операциям и вычисляем конвеерно

Анонимус, /r/ код на Лиспе, ну так. чисто поржать потому как (defvar *i* 5) (+ (incf *i*) (incf *i*)) уверенно дает 13.

правильный ответ - 13, в с++-компиляторах получается 14 из-за блядской оптимизации.

Ты не шариш. В блядском c++ операция префикс-инкремента возвращает ссылку на обработанный объект, в отличие от пост-инкремента, которая и возвращает новый объект. (Это корректное поведение для, потому что при перегрузке инкрементов постфиксная версия юзает префиксную.) Поэтому и 14, соответственно 13 будет там, где префикс-инкремент возвращает новый объект.
Давай по шагам для слоупоков. Первый инкремент увеличивает i до шести и возвращает ссылку на i. Второй инкремент увеличивает i до семи и возвращает опять-таки ссылку. Оператор сложения берёт две ссылки и складывает i c i, то есть 7 с 7. Поэтому 14. Так?
Ну, если без доябывания до возврата ссылок во встроеных типах, то да. СутьЪ: ты изменяешь один объект, а не производишь новый. Например, (глядя на примеры в статье) java и c# при работе с элементарными типами возвращают новые объекты вне зависимости от ориентации ++, и на выходе есь 13. Впрочем, за такой код лопатой по рукам, да.
Насилу вкурил. Может добавить в статью, что прикол в возвращении ссылки, а не значения в C++?
Ты, в честь первого арпеля, смешься что-ли? Картинка сверху повествует обо всем этом даже лучше.
По картинке не очевидно, что инкремент возвращает ссылку, а не значение.
Капитан Очевидность Префиксный аргумент возвращает ссылку, но говорить об этом можно только для не-встроенных типов. Встроеным по барабану, посчитайте i++ + i++ для int и struct myInt{int x;} - получите разницу. Так-то!

>>int i = 5; i = (++i) + (++i) + (++i);
>>GCC. На выходе — 22. ШО ЗА ЁБАНЫЙ ЖЕ Ж НАХУЙ?

Я не считаю себя программистом, но мысли есть…

Итак, на входе gcc 4.3.3
int i=5; i = (++i) + (++i);
На выходе i=14
С точки зрения C++ это совершенно логичный ответ. Левый инкремент по-идее имеет наивысший приоритет среди всех операций (наряду с декрементом). Соответственно, по-идее это работает так:
1) ++i: i=6
2) ++i: i=7
3) i + i: i=14

Пример 2
int i=5; i = (++i) + (++i) + (++i);
По-идее это должно работать так
1) ++i: i=6
2) ++i: i=7
3) ++i: i=8
4) 8+8+8: i=24
Но выходит действительно 22. Вопрос в том, почему

Потому что ((++i) + (++i)) + (++i) => ( (5+1=6->7) + (6+1=7))+ (7+1=8)=(7+7)+8 - т.е. сводим к двухместным операциям add и вычисляем конвеерно
потому что отключите оптимизации кода долбаебы, и будет 24.
(в пределах операции сначала вычисляються побочные эффекты)

Пример 3
int i=5; i = (++i) + ((++i) + (++i)); (вторую часть мы взяли в скобки, изменив тем самым порядок сложений)скобки не меняют порядок применения побочных эффектов, просто теперь выражение в скобках считается отдельным выражением.
На выходе, внимание, 24!
Вывод — что-то явно не так с порядком выполнения операций.

А здесь уже есть бинарная операция,но сначала вычисляются побочные эффекты, i'=6 (i'=7 i'=8) => 8 + 8 + 8=24

Пример 4
int i=5; i = ++i*2 + ++i;
Это должно работать так:
1) i++: i=6
2) i++: i=7
3) i=i*2+i: i=7*2+7=21
Как бы не так! На выходе 19!

ничем ни отличается от примера 1 (++i*2 + ++i)=(6*2 + 7)=19
а вот хуй, компилер вц11, оптимизиции отключены.
int i = 5;
012013BE mov dword ptr [i],5 ; i = 5
i = ++i*2 + ++i;
012013C5 mov eax,dword ptr [i]
012013C8 add eax,1 ; ++i
012013CB mov dword ptr [i],eax
012013CE mov ecx,dword ptr [i]
012013D1 add ecx,1 ; ++i
012013D4 mov dword ptr [i],ecx  ; i == 7
012013D7 mov edx,dword ptr [i]  ; edx == 7
012013DA mov eax,dword ptr [i]  ; eax == 7
012013DD lea ecx,[eax+edx*2] ; i = 7 + 7*2
012013E0 mov dword ptr [i],ecx ; i == 21
return 0;

Моё предположение. gcc весьма странным образом вычисляет значение выражения. К примеру, возможно, выражение разбивается на части в соответствии с уровнями приоритетов операций и вычисляется по частям. При этом не учитывается тот факт, что в самом процессе вычисления выражения могут поменяться значения входящих в него переменных. Если принять это предположение, всё становится на места:

Шо за хуйня? И не лень столько хуиты писать?
Алгоритм
1.Расставляем скобки в соответствии с приоритетом операций / * + - и без всяких там блять инкрементов
2.Берем первые два операнда
3.Применяем побочный эффект первого операнда.Если операнд сложный - вычисляем выражение в скобках этим-же алгоритмом.
3а.Тоже для второго операнда
4.вычисляем двуместную операцию. результат => AX
5.Находим следующий операнд(если есть , иначе - выход)
6 применяем его побочные эффекты
7.operation(AX,след.операнд)
8.goto п.6
проще говоря если представить списком
1.разбиваем его по приоритетам
2.потом на двуместные операции 5+5+5+5=((((5)+5)+5)+5)
3.для каждой двуместной сначала применяем побочные эффекты(с углублением в список) - потом вычисляем результат
4. ...
5. PROFIT!
на Лиспе без учета типа операции это примерно (defun calc(l &optional Z)((if (NULL (car l)) Z (progn (side-effect (car l)) (сalc (cdr l) (operation Z (car l))))
Не знаете ассемблерную команду [add|sub|mul|div] ax,op? Не знаете что такое рекурсия? Не считаете себя программистом, но хотите принести пользу человечеству?
Вам поможет БИОРЕАКТОР! Спрашивайте в аптеках города...

Пример 2
int i=5; i = (++i) + (++i) + (++i);
1) ++i: i=6
2) i + ++i:
2.1) ++i: i=7
2.2) i + i = 14 (в этот момент мы потеряли i как одно из слагаемых-переменных, и получили вместо этого сумму как константу, которая уже не поменяется при следующем инкременте i), i=7
3) 14 + ++i:
3.1) ++i: i=8
3.2) i=14 + i: i=14+8=22

Пример 3 отличается от 2 дополнительными скобками
int i=5; i = (++i) + ((++i) + (++i));
1) ++i: i=6 (это то ++i, которое самое первое)
2) ((++i) + (++i))
2.1) ++i: i=7
2.2) ++i: i=8
2.3) i+i: 16 (тут мы получаем уже другую константу), i=8
3) i=i+16: i=8+16=24

Пример 4
int i=5; i = ++i*2 + ++i
1) ++i: i=6
2) i*2: 6*2=12, i=6 (обратите внимание, мы уже получили константу вместо переменной как в оригинальном примере. Дальнейшие манипуляции с i никакого влияния на нее не окажут)
3) ++i: i=7
4) i=12+i: i=12+7=19. Сходится

PS: Гораздо более интересно выглядят манипуляции с ПРАВЫМ инкрементом (он должен иметь НАИМЕНЬШИЙ приоритет с т.з. C++) Интересно то, что результаты по нему расходятся для gcc и для perl.

Блять, а кто сказал что это с++, gcc умеет компилить исходники на разных языках - теже результаты вы получите и для Си.


Содержание

[править] правильный ответ

пипец вы ламерье. для начала усвоим что ++j и j++ это разные вещи.

  • a=++j - означает 1. j=j+1 2. a=j (который кагбе уже плюсанулся в первой операции)
  • a=j++ - означает 1. a=j 2. j=j+1 (таким образом инкременция происходит уже после присвоения a=)
  • отсюда. a = ++j + ++j - означает
    • j=5; j=(++j[тут уже 6]) + ++j[тут уже 7]);
    • таким образом j=5; j=(6 + 7]);
    • верный ответ j= 13.
  • учите матчасть, школие. это православный каноничный ответ. учите про приоритет операций (унарный предварительный инкремент ++j имеет высший приоритет исполнения)

Гы! Вот я ровно так думал, а потом ВНЕЗАПНО оказалось, что ++j возвращает не значение, а ссылку. В итоге — таки 14.

Ты не совсем прав. Для встроеных типов нет конкретных правил возвращения, их действия определяет компилятор. То есть, может там ссылка и не возвращается вовсе, а весь код с этой переменной анализируется несколько раз. Но поведение должно быть такое, да. Кстати, на следующем примере действительно можно выловить ссылку:
#include <iostream>
 
int main()
{
  int  i  = 5;
  int& ri = ++i;
  ++i;
 
  std::cout << ri; // здесь будет 7, пыщь-пыщь!!1
}
Что там компилятор на сама деле делает — тайна великая для меня есть. Тем более, его поведение неопределено. Возвращение ссылки в случае двух слагаемых просто мое объяснение происходящего, вроде не противоречащее наблюдаемым фактам.

Ссылка ссылкой, но ++i + ++i + ++i даёт 22(7+7+8), а ++i + ++i + ++i + ++i - 31(7+7+8+9). Так что, самый настоящий андефайнд бихейвиор.

А кто-то с этим спорит? В стандарте нопейсано же. Об самом операторе речь.
Всё решает оптимизатор. Когда он решит из ссылки достать значение и запихать его в стек или в регистр - это его дело. По идее + имеет приоритет ниже, чем ++, поэтому должны вычислиться два ++, затем только их ЗНАЧЕНИЯ могут кому-то понадобиться, а поскольку их надо ещё и достать по ссылке, которая между прочим одинакова для обоих ++, вот тут то и получается интересно, особенно если оптимизатор решит это всё оптимизировать. Интуиция говорит, что результат ++i - это не ссылка, а i+1. Логика подсказывает, что при сложении чисел различной чётности получается полюбому нечётное число. Если бы было написано так: add(&(++i), &(++i)), то вопросов было бы меньше.

[править] настоящий правильный ответ

Предыдущий ответ нисколько не каноничный, он не лучше всех предыдущих. Дело здесь не в приоритете, конечно, а в валидности программы.

Стандарт языка С++ ISO/IEC 14882 от 1998г. вводил понятие sequence point [1.9:7,11,16], между которыми (скалярная) переменная может быть изменена только один раз [5:4], и там как раз приведены примеры, что i=++i + 1; // the behavior is unspecified. Выражение ++i никоим образом sequence point не вводит (если только это не вызов функции "перегруженный operator++" для пользовательских типов, т.е. не в этом случае).

В редакции стандарта от 2003г. это unspecified behavior стало[1] undefined, т.е. компилятор теперь имеет полное право вписать в переменную значение 42, вставить в программу код, форматирующий веник или взрывающий ваш монитор.

С этого момента, собственно говоря, вопрос перестает быть техническим и становится "коммуникационным".

Так как выражение вида i = ++i + ++i; с точки зрения языка невалидно, нельзя однозначно судить о том, что же хотел сказать автор, написав это злополучное выражение. (А вы попробуйте подойти к прохожему на улице и сказать "абырвалг!" (а в случае с включенными оптимизациями это и вовсе выпилит все гласные из и так невнятного слова). Что за этим последует, можно только гадать. Вполне возможно, что вам "отформатируют веник".)

  • Искренне ваш, Капитан Не Такая Очевидность.


  1. оно и было. пример с undefined не соответствовал остальному тексту, и примеры нормативными не являются

[править] Частности

Правиильный ответ выше. В этом разделе хуита, ибо рассматривает конкретный результат конкретного компилятора.

[править] ОЛСО

С точки зрения функциональной прагмиды:

++i - функция, возвращающая i + 1 с сайд-эффектом в виде i = i + 1

++i + ++i есть функция сложения с аргументами - результатами функций ++ с аргументом i

аргументы не могут вычисляться параллельно, т.к. при сайд-эффекте будет блокировка i

т.е. аргументы вычисляются один за другим, но похуй в каком порядке

В этом случае результатом выполнения сложения будет 13. Ежели без слайд-эффекта, то 12.

Большая просьба к автору, определиться сайд-эффект это или сЛайд-эффект и объяснить: что это за ХРЕНЬ?!
Очевидно же, что последовательное выполнение всех действий с операндом с соответствующим блокированием оного для последующих операций, пока предыдущая не будет выполнена

[править] хуита

 
VC2008 Express
#include "stdafx.h"
int _tmain( int argc, _TCHAR* argv[] )
{
	int i = 5;
	return ++i + ++i;
}

Ответ:

Поток 'Поток Win32' (0x2b84) завершился с кодом 14 (0xe).

От такая хуйня, малята.

«На самом деле»

    i = ++i + ++i + ++i;

Сей код в .ехе (компиль - унылый DevCPP) смотрится как:

LEA EAX,DWORD PTR SS:[EBP-4]
INC DWORD PTR DS:[EAX]
LEA EAX,DWORD PTR SS:[EBP-4]
INC DWORD PTR DS:[EAX]
MOV EAX,DWORD PTR SS:[EBP-4]
MOV EDX,DWORD PTR SS:[EBP-4]
ADD EDX,EAX
LEA EAX,DWORD PTR SS:[EBP-4]
INC DWORD PTR DS:[EAX]
LEA EAX,DWORD PTR SS:[EBP-4]
ADD DWORD PTR DS:[EAX],EDX
Сначала считает первые два операнда, потом только едем дальше. Это все эти ваши хай левел языки, в Великом и Могучем такого конечно быть не может... Чем гадать - лезем в код и смотрим сами.


[править] Delphi++

Насилу вкурил что к чему. Благо, расово верный объектный паскаль избавлен от таких заебов. Понимабельности коду такая хуета ниразу не добавляет. Программеров, написавших такое в моем отделе, ждет анальная окупация навечно.


Delphi вообще няшечка в подобных вопросах. Там нет кейворда volatile, переупорядочивания операций, strict aliasing rule, etc - вместо этого всё пусть и чуть субоптимально, но соответствует интуитивным ожиданиям. Но вот что-то он никуда не пролазит: ни на 64 битные платформы, ни в мобильные девайсы, а до недавнего времени не было даже нормальной поддержки уникода.
А вообще, непоправимое случилось не когда появился такой синтаксис в языке Си, а когда скриптовые языки и Java с дуру унаследовали этот синтаксис.
В ANSI PASCAL вместо++ есть логические правильные функции Inc() и Dec(). В виду сего их поведение полностью предсказуемо. В отличие например значения счетчика цикла. Он прямо заявлен как UB.
Да просто во времена последней расово верной D7 все было ориентровано на win32, а после семерки проект скорее мертв чем жив, и многочисленные попытки его оживить всегда заканчивались фэйлом. Виновата в этом прежде всего постоянная смена владельца. Тем не менее традиционные оконные приложения на ней пишут до сих пор, хотя число стартапов стремится к нулю.
Виноват в этом не дельфи, и даже не Билл Гейтс, а безвестный инженер которому стукнуло в голову добавить в ассемблер PDP11 инструкции ++  и  ++
Да лаааадно, ничего не мертв, оформили же Win64 компилятор, и потихоньку внедряют кросплатформенность, вроде ж можно уже и под Mac ваять приложения. Один FL Studio чего стоит


Так, хватит страдать всякой хуитой паскалями и теорией, в делфях, в системном модуле, есть такая функция (на асме):

function InterlockedIncrement(var I: Integer): Integer;

asm

     MOV   EDX,1
     XCHG  EAX,EDX
LOCK XADD  [EDX],EAX
     INC   EAX

end;

Делаем i:=InterlockedIncrement(i) + InterlockedIncrement(i) и получаем (спойлер: 13).

[править] кто тут умный

нам препод вынес мозг и буду весьма благодарен если объясните как такой майндфак получает от 22 до 43 int i=5; i+=i+=i++ + ++i;

вабсче лучшая идея - это изучить дебаггер и сабж статьи.
тащемта всё происходит вот так, например.
int i = 5;
013413BE mov dword ptr [i],5 ; i = 5
i += i+= i++ + ++i;
013413C5 mov eax,dword ptr [i]
013413C8 add eax,1 ; i++
013413CB mov dword ptr [i],eax ; i == 6
013413CE mov ecx,dword ptr [i]
013413D1 add ecx,dword ptr [i] ; i += 6
013413D4 add ecx,dword ptr [i] ; i += 6
013413D7 mov dword ptr [i],ecx ; i == 18
013413DA mov edx,dword ptr [i]
013413DD add edx,dword ptr [i] ; i += i
013413E0 mov dword ptr [i],edx ; i == 36
013413E3 mov eax,dword ptr [i]
013413E6 add eax,1 ; i++
013413E9 mov dword ptr [i],eax
return 0;
итого i == 37



[править] VS C++ реализация

Сначала разберемся с приоритетами операций (в порядке возрастания и только встречающиеся в примерах)
0. +=
1. +
2. *
3. Префиксный ++

Теперь будем разбирать сами выражения:
1. int i = 5; i = ++i + ++i;
в соответствии с предоставленными выше приоритетами это i|++|i|++|+ ('|' - просто разделитель)
Выше показано как ++ на ассемблере реализуется:

LEA EAX,DWORD PTR SS:[EBP-4]<br />
INC DWORD PTR DS:[EAX]<br />

Т.е. инкрементится значение по адресу i, откуда получается что после i|++|i|++ значение i = 7. Осталось только сложить и получим 14

2. int i = 5; i = (++i) + (++i) + (++i). Вообще-то на скобки можно положить, т.е. рассматривать просто i = ++i + ++i + ++i, но со скобками более читабельно :)
Получаем i|++|i|++|+|i|++|+
Вот откуда получается 7+7+8 = 22 - сначала значение i становится равным 7 (первые два ++), потом идет операция +, далее i становится равным 8 (третий ++), и наконец последняя сумма 14+8 = 22

Далее покороче :)
3.int i=5; i = (++i) + ((++i) + (++i));
i|++|i|++|i|++|+|+
Т.е после всех ++ в i=8 и далее два раза складываем, откуда и получается 24

4. int i=5; i = ++i*2 + ++i;
i|++|2|*|i|++|+
Итог 6*2 + 7 = 19

5.int i=5; i = ++i + ++i + ++i + ++i
i|++|i|++|+|i|++|+|i|++|+
Итог 7 + 7 + 8 + 9 = 31

6. int i = 0; i += i++ + ++i
Тут постфиксный ++ не влияет вообще ни на что в выражении, он выполняется после всех операций:
i|i|i|++(префиксный)|+|+=|++(постфиксный)
Т.е. 1+1=2 потом 1+=2 что равно трем и в конце ++, откуда ответ 4.
1. 1+1 = 2
2. i+=2 равно 3 (i=1)
3. i++ = 4

7. int i=5; i+=i+=i++ + ++i;
i|i|i|++(префиксный)|+|+=|+=|++(постфиксный)
1. 6+6=12
2. i+=12 равно 18 (i=6)
3. i+=18 равно 36 (i=18)
4. i++ = 37

Проверка на VS 2010 показала, что написанное выше — полный пиздеж.

[править] Python

Кто шарит посмотрите, нужны ли тут скобки: (НИЧЕГО+НИЧЕГО+i)+(НИЧЕГО+НИЧЕГО+i) Если в Питоне нет очень сильного пробельного колдунства, то должно же быть без скобок: НИЧЕГО+НИЧЕГО+i + НИЧЕГО+НИЧЕГО+i


http://ideone.com/8INWz Таки 13

[править] Python на списках

def inc(a):
    a[0] += 1
    return a
 
def add(a, b):
    return [a[0] + b[0]]
 
i = [5]
i = add(inc(i), inc(i))
print i

http://ideone.com/bj4RJQ Таки 14.

[править] Python, отдельный класс=

class Foo:
    def __init__(self, num):
        self.num = num
 
    def inc(self):
        self.num += 1
        return self.num
 
i = Foo(5)
print(i.inc() + i.inc())

[править] js

Вот блин: javascript:var i=5;alert(++i + ++i)

13

А мозги-то перловые -- в уме 14 получилось :)

[править] Примечания о питоне и руби

Не уверен насчет питона, а про Руби примечание точно писал какой-то дятел, не открывший для себя существование в природе унарных операторов. А коль он такой умный рубист, пуст скажет, где описан метод «+» класса НИЧЕГО. Единственное НИЧЕГО, наличествующее в этом обсуждении — это у автора примечания в голове, а остальное — 4 унарных плюса.

[править] gcc мудрит чего-то....

Префиксный инкремент/декремент является операцией наивысшего приоритета, и поэтому должен выполнятся раньше всех других операций. Это по логике и програмер, который с ней дружит, такого поведения и ожидает. Т.е.
i = ++i + ++i; => 14
i = ++i + ++i + ++i; => 24
i = ++i + ++i + ++i + ++i; => 36
...
ну вы понели
Количество и месторасположение скобок в выражении результат не меняет, ибо скобки в данном выражении (где все бинарные операции одного и того же приоритета) приоритет операций изменить не могут.
Опять же, это по логике.
Ну, а если gcc выдает что-то иное, значит он где-то и как-то от этой самой логики уклоняется. GNU == ЧСВ => true.

[править] Это ещё фигня. Вот это уже по-жестче

z=++i+i+++i;

И обязательно без пробелов.
; //
; (++i) + (i++) + i;
; i = 5;
; 1. ++i => 6,
; 2. z = (6) + (6) + (6) => 18
; 3. i++ => 7;
;

Неоднозначность понимания последних плюсов, чего мелочится, сразу так:
z=++i+i+++++i;

[править] i++ + ++i

Чем этот вариант не приглянулся? —195.69.156.252 13:41, 20 августа 2012 (MSK) Тут всё понятно 5 + (1 + 6) = 12 Справедливо для C# и проверено в VS 2013 (а в С/С++ ваще хуй проссышь что получается)

[править] а на самом деле

чтобы избежать ub, достаточно объявить i как volatile int i;

[править] TurboC и GCC

допустим int i=3;

тут вывод одинаковый для обоих:

++i * ++i => 25 and i=5

а тут:

TurboC: ++i * ++i * ++i => 216 and i=6

GCC: ++i * ++i * ++i => 150 and i=6

ну в TurboC понятно что 6 * 6 * 6

а как в GCC получается 150, нихуя не понятно

cкорее всего 5 * 5 * 6 но КАК?

c volatile int i получается вообще 120 (в ТurboC все те же 216)

[править] По поводу int i = 0; i += i++ + ++i;

«K&R определил += как разновидность именно оператора присваивания, а не краткую форму записи i=i+…, то есть к инстанции «выражение» относится всё, что справа от +=. Поэтому += можно не бояться, так как предынкремент вычисляется до значения выражения, затем вычисляется выражение, затем — сразу же и никак иначе — постинкремент, а потом уже мы покидаем инстанцию данного выражения и используем его результат по назначению (в данном случае — для операции +=).»

Жуткое заблуждение! Постинкремент может вычисляться где угодно в этом выражении. Компилятор обязан вычислить все побочные эффекты (в т.ч. постинкремент) лишь на следующей точке следования (sequence point), коей тут является точка с запятой. Внутри выражения точки следования нет, а это значит, что постинкремент может вычислиться как до оператора +=, так и уже после. main {

   int i=1;
   printf("%d ", i+=i++);

}

Этот код и на gcc, и на MSV C++ Compiler выдает 2. Это значит, что постинкремент вычислился аж после printf.

[править] Lazarus

Может, кому пригодится. Это связанная проблема - неопределённость при вычислении выражений. Цитирую Lazarus Free Pascal Reference Guide:

Remark: The order in which expressions of the same precedence are evaluated is not guaranteed to be left-to-right. In general, no assumptions on which expression is evaluated first should be made in such a case. The compiler will decide which expression to evaluate first based on optimization rules. Thus, in the following expression:
a := g(3) + f(2);

f(2) may be executed before g(3). This behaviour is distinctly different from Delphi or Turbo Pascal.

If one expression must be executed before the other, it is necessary to split up the statement using temporary results:

e1 := g(3);  
a  := e1 + f(2);

Кто не умеет в буржуйский, перевожу:

Примечание: Порядок, в котором вычисляются выражения в каждом конкретном случае, не обязательно есть «слева направо». Более того, в таких случаях нельзя делать каких-либо предположений. Компилятор самостоятельно решит, какое выражение вычислить первым, основываясь на правилах оптимизации кода. Поэтому при выполнении такого фрагмента кода
a := g(3) + f(2);

функция f(2) может быть вызвана перед вызовом g(3). Такое поведение заметно отличается от Delphi или Turbo Pascal.

Если одно выражение ДОЛЖНО быть вычислено раньше другого, необходимо разбить выражение на части при помощи вспомогательных переменных:

e1 := g(3);  
a  := e1 + f(2);

А я-то понадеялся на верность традициям... В общем, теперь FPC следует опасаться так же, как С-подобных языков. Если у кого есть что дополнить, пишите в эту ветку.

[править] Batch

Получил 10, шо за ёбаный ж ты нахуй?

Код:

set /a i=5
set /a c= ++i + ++i
echo %c%
pause
Персональные инструменты
Счётчики
Контакты / Реклама