singlepost

t = ++t + ++t << На главную или назад  

int t = 10;
t = ++t + ++t;

t = 24

Но:

int t = 10;
t = –t – –t;

t = 0

Объясните, в чем разница сложения и вычитания?

48 ответов в теме “t = ++t + ++t”

  1. 47
    Слава Трушкин ответил:

    gcc -Wsequence-point …
    избавляемся от неопределенности

  2. 46
    Офыволдшощзй Фыошщфышщоаргк ответил:

    #44
    Роман Воробец 20 авг 2008 в 14:46

    ОФФТОП: Не только. Также определен порядок вычислений для операций && и ||

  3. 45
    Ростислав Чутков ответил:

    Роман Воробец, верно. но тут как раз речь о приоритетах операций =)

  4. 44
    Роман Воробец ответил:

    М-да, сколько безграмотных :)
    Порядок вычисления выражений, если дело не касается приоритетов операций, определён только при использовании оператора ",".
    Вот, к примеру:
    foo(shared_ptr<bar>(new bar(x)), shared_ptr<bar>(new bar(y)))
    где здесь ошибка? ;)

  5. 43
    Кирилл Быков ответил:

    2 Ростислав.
    Ага. Согласен. Должен. И если он считывает значение переменной только один раз, то должен учесть такой эффект, и самостоятельно декрементировать результат до значения 23, которое и есть правильное, ибо получается в образцовом варианте (т.е. в варианте без оптимизации).

  6. 42
    Офыволдшощзй Фыошщфышщоаргк ответил:

    >Еще как подлежит, вообще volatile не имеет отношения к оптимизации никакого.

    Имеет. volatile значит, что переменная может быть изменена где-то еще (в другом потоке/аппаратно/итп), отсюда следует, что ее следует считывать заново каждый раз, когда нужно ее значение, то есть нельзя использовать оптимизацию, когда используется ранее считанное значение, если оно не изменялось. (ну и наоборот: при каждом присваивании нужно ее новое значение в нее записывать. то есть если i=2; i=3; то нельзя это оптимизировать и первое присваивание выкинуть, ибо volatile).

  7. 41
    Ростислав Чутков ответил:

    Да, неправ, согласен, volatile действительно влияет именно на отключение "константных" предвычислений.

    Правда в данном случае никакой речи о подобных оптимизациях нет, т.к. выражение считается в одном потоке, и компилятор, уж наверное, должен знать про все side-effects.

  8. 40
    Ростислав Чутков ответил:

    #39
    >В случае с инкрементами/декрементами – сначала эти самые инкременты/декременты, потом сложение.

    Я об этом же.

    >Суть в том, что при включенной оптимизации значение переменной, которая входит дважды в выражение, считывается из нее только один раз

    какой оптимизации? не припомню чтобы какая-нибудь комбинация параметров оптимизации в VS приводила к другому результату вычислений.

    >Если же переменная volatile, то оптимизации она не подлежит

    Еще как подлежит, вообще volatile не имеет отношения к оптимизации никакого.

    Вообще не понимаю какие могут быть сомнения, все выражения вычисляются последовательно, значения берутся с учетом всех side effects, операции требуют вычичления своих аргументов. если gcc считает по-другому то это его косяки.

  9. 39
    Офыволдшощзй Фыошщфышщоаргк ответил:

    а оптимизация на результат влияет, например, если забыть объявить переменную volatile там, где это нужно.

  10. 38
    Офыволдшощзй Фыошщфышщоаргк ответил:

    #36
    Ростислав Чутков 20 авг 2008 в 13:38
    ,
    выражение вычисляется в порядке приоритета операций. в твоем случае – сначала умножение, затем сложение.
    В случае с инкрементами/декрементами – сначала эти самые инкременты/декременты, потом сложение.
    Суть в том, что при включенной оптимизации значение переменной, которая входит дважды в выражение, считывается из нее только один раз, и в данном случае это происходит после обоих инкрементов, получается 24. Если же переменная volatile, то оптимизации она не подлежит, и ее значение берется каждый раз заново. То есть: вычислили левый операнд, в процессе этого один раз ее инкрементировали; запомнили ее значение (11); вычислили правый операнд, запомнили его (12); сложили – получается 23.

  11. 37
    Артём Шалхаков ответил:

    забавно.

    в D сделано очень просто: It is an error to depend on order of evaluation when it is not specified. (и приводится список, что и в какой последовательности вычисляется)

  12. 36
    Офыволдшощзй Фыошщфышщоаргк ответил:

    тут тоже переменная меняется во время вычисления.

  13. 35
    Ростислав Чутков ответил:

    Почему бы не усомниться тогда что
    5*3 + 3*1 считается не как 5 * (3 + 3) * 1? тут такая же ситуация.

    в t = ++t + ++t; мы имеем справа две ветки операции плюс, каждая из которых содержит инкремент. для того чтобы вычислить значение выражения, нужно получить значение обоих веток ДО применения операции, соответственно оба инкремента должны выполниться ДО операции плюс, и результат 24 абсолютно верный и логичный.

    Вообще тот кто ставил вопрос наверное имел в виду
    t = t++ + t++;
    вот тут результат немного более интересный.

  14. 34
    Офыволдшощзй Фыошщфышщоаргк ответил:

    Разберу на примере GCC
    23 будет, если t объявлено как volatile. тогда все оптимизации с этой переменной отключаются, и каждый раз при вычислении выражения берется ее текущее значение (первый раз 11, второй раз 12).
    Если нет, то вследствие оптимизации значение переменной берется только один раз, после обоих инкрементов.

  15. 33
    Кирилл Быков ответил:

    Оптимизация, по определению, не должна влиять на результат. Она должна влиять на скорость и ресурсные требования. volatile ── для тех случаев, когда переменная может меняться где-то параллельно, например, в другом процессе/потоке/нити. А тут имеется в виду единственный вычислительный поток.

  16. 32
    Кирилл Быков ответил:

    Всё равно 23 должно быть. Даже если функция.

  17. 31
    Слава Трушкин ответил:

    Если оператор — это функция, а операнды — это аргументы, то вариант с 24 справедлив:

    ++t + ++t := sum(++t, ++t)

  18. 30
    Кирилл Быков ответил:

    Всяко 3 результат. Инкремент ведь раньше выполнится, нет?
    Значение постинкремента =1, хотя t уже =2.
    Затем к t(=2) прибавляется 1, и результат t=3

  19. 29
    Владимир Леонов ответил:

    Ребят, да вы че? Ни разу чтоли не сталкивались с такими операциями?
    есть еще более простой, наверное даже самый простой пример:

    int t= 1;
    t += t++;

    Чему будет равен результат? Этого вам никто не скажет, потому как все зависит от компилятора. Почитайте статьи на тему "Точки следования" и "Undefined Behavior" в них как раз и рассказывается про такие интересные случаи.

    одна из статей:
    //alenacpp.blogspot.com/2005/11/sequence-points...

    И совет на будущее: никогда не пишите так в своих программах :)

  20. 28
    Кирилл Быков ответил:

    Логичнее вариант 1:
    1. ++t; // t == 11 и (++t) == 11
    2. ++t; // t == 12 и второй (++t) = 12
    3. ++t + ++t; // 11 + 12 = 23
    Вариант 2 вообще полная чушь.
    С вариантом 3 ещё можно смириться. А вообще, не очень хорошо, что стандарт допускает такие разночтения.

  21. 27
    Кирилл Быков ответил:

    Во! Согласен с Павлом Scavenger Потаповым, всё именно так, как думаю я.

  22. 26
    Павел Потапов ответил:

    2Вячеслав Kovyl Ковалёв
    Здравая логика говорит о том, что должно быть 23 (все-таки результаты двух последовательных инкрементов должны отличаться) :) А на практике 24 получается в силу того, что t записывается в один регистр процессора и дважды в нем инкрементируется, после чего складывается.

  23. 25
    Владимир Unnamed ответил:

    >> Насколько мне известно, стандарт в данном случае не указывает
    >> какой-то конкретный порядое вычисления, и "правильны" несколько
    >> результатов.

    Это еще называют Undefined Behaviour

  24. 24
    Олег Андреев ответил:

    Эту задачку для разминки мозга я отношу к категории "перлизмы". Операторы @++ и @– обладают нечеловечески дурацким поведением. Опытные люди привыкли, а неопытные взрывают себе мозги.

  25. 23
    Вячеслав Ковалёв ответил:

    Безусловно, нужно ссылаться на стандарт, но еще существует здравая логика. Правилен все-таки третий вариант…

  26. 22
    Виталий Русинов ответил:

    имхо, лучше так не писать) кроссплатформенность пропадает))

  27. 21
    Саня Какбэя ответил:

    ржунимагу)))

  28. 20
    Павел Потапов ответил:

    Результат таких выражений зависит от реализации в компиляторе. Оптимизация, однако ;)

  29. 19
    Евгений Гаврин ответил:

    Листал с коллегой по работе последнюю редакцию стандарта – на эту тему не нашли ни слова. Так что дается на откуп разработчику компилятора =)

  30. 18
    Ваня Яни ответил:

    3.4.5

  31. 17
    Ванько Родригез ответил:

    >> GCC выдаёт 24
    Хм… какая версия? Я вроде помню, что он работает по первому сценарию.

    Кстати, знает ли кто, как оно в стандарте определено (и определено ли вообще)?

  32. 16
    Жека Кирпичев ответил:

    О правильности можно говорить только ссылаясь на соответствующую секцию стандарта. Насколько мне известно, стандарт в данном случае не указывает какой-то конкретный порядое вычисления, и "правильны" несколько результатов.

  33. 15
    Ваня Яни ответил:

    GCC выдаёт 24

  34. 14
    Ваня Яни ответил:

    Я считаю вариант 3 наиболее правильным

  35. 13
    Ростислав Чутков ответил:

    приоритет-то у декремента выше:

    t = –t – –t;
    004113C5moveax,dword ptr [t]
    004113C8subeax,1
    004113CBmovdword ptr [t],eax
    004113CEmovecx,dword ptr [t]
    004113D1subecx,1
    004113D4movdword ptr [t],ecx
    004113D7movedx,dword ptr [t]
    004113DAsubedx,dword ptr [t]
    004113DDmovdword ptr [t],edx

  36. 12
    Ванько Родригез ответил:

    Дима, выполнятся может так по разному. Например, t = ++t + ++t
    Вариант 1:
    1. ++t; // t == 11 и (++t) == 11
    2. ++t; // t == 12 и второй (++t) = 12
    3. ++t + ++t; // 11 + 12 = 23

    Вариант 2:
    1. ++t; // t == 11 и оба (++t) == 11
    2. ++t + ++t; // 11 + 11 = 22

    Вариант 3:
    1. ++t; // t == 11
    2. ++t; // t == 12
    3. ++t + ++t; // 12 + 12 = 24

    Вариант 3 мне не попадался, но 1 и 2 второй существуют в примерно равных пропорциях.

  37. 11
    Слава Трушкин ответил:

    ыыы) я знал, что здесь есть подвох.

  38. 10
    Dima Zlobodenjuk ответил:

    Уже подумалось : может забыл чего… Потому что как не считал (руками) получается 23 и 1

  39. 9
    Алексей Самулеенков ответил:

    Кстати, а откуда именно такие результаты выполнения кода? Посчитал – получилось 23 и 1 соответственно. C# показал то же самое.

  40. 8
    Константин Дерец ответил:

    кстати, экспериментально доказано, что результат такого рода операция зависит от компилятора.

  41. 7
    Ваня Яни ответил:

    int t = 10;
    t = t+++t;

    Чему равно t и почему?

  42. 6
    Александр Диденко ответил:

    Нечто подобное видал в книжки Страуструпа "Язык C++"

  43. 5
    Ростислав Чутков ответил:

    О нет, n – n = 0 ?! Ужас, страшно жить

  44. 4
    Слава Трушкин ответил:

    Жека jkff Кирпичев, спасибо. рабочий день заканчивается)

  45. 3
    Офыволдшощзй Фыошщфышщоаргк ответил:

    странный вопрос.

  46. 2
    Артем Валиев ответил:

    ни в чем оО
    где ты тут разницу увидел (кроме чисто идеологической разницы м/у плюсом и минусом, конечно :) ?

  47. 1
    Жека Кирпичев ответил:

    В первом случае выполнилось
    ++t; ++t; t = t+t;

    Во втором случае
    –t; –t; t = t-t;

    Никакой разницы нет.

Клуб программистов работает уже ой-ой-ой сколько, а если поточнее, то с 2007 года.