Превратности вычислений

    Имеется следующий фрагмент кода:

    i = 5;

    i = ++i + ++i;

    Java и PHP выдают результат 13

    C++ — 14.

    Как вы считаете, какой результат является правильным? Разъяснения приветствуются.

    Комментарии 41

      0
      Если по Страуструпу, то выражения должны разбираться таким образом, чтобы получилось как можно большее выражение (по длине) и синтаксически верными, т.е. должно быть (ну это как я думаю) (((++i)++)+i), т.е. 13
        +5
        Конечно в большинстве случаев пробелы не играют роли, но это не тот случай. Выражение должно разобраться именно как (++i)+(++i).
        А то что в С++ получается 14, это просто детали реализации модели вычислений (не парсера) конкретного компилятора, насколько я помню, по крайней мере в С, в спецификации строго не оговорено как такое выражение должно вычисляться. И более того, насколько я помню универский курс, в различных компиляторах мы получим различные значения :)
          0
          Единственный здравомыслящий комментатор к этому топику. Кроме меня :D
        +1
        в С++ и Перле 14, в PHP и Яве - 13.
        А вообще, это боян.
        А вообще вообще, я тоже хотел узнать, почему :-)
          0
          Как раз-таки в обсуждении баяна i+++i я и прочитал про как можно большую длину
            +1
            Я вообще это имел ввиду, когда про боян написал :)
              0
              Спасибо за ссылку :)) Не видел раньше.
          0
          UPD: главное, что если в С++ или Перле выражение
          i = ++i + ++i;
          заменить на
          i = ++i + ++i + ++i;
          то результат будет очень неожиданным!
            0
            зря пробелы ставите :) сбиваете с толку.
            0
            вариант один
            1) ++i + ++i (i=5)
            2) i + ++i (i=6)
            3) i + i (i=7)

            вариант два
            1) ++i + ++i (i=5)
            2) 6 + ++i (i=6)
            3) 6 + 7

            Внимание вопрос!
            Какой вариант правилен?
              0
              В С верен первый вариант. в php - второй. Это особенности языка.
                0
                многие говорят, что компилятора, а не языка.
                  +3
                  Дело в том, что си при пре-инкременте увеличение происходит до всего оператора , т.е. в си i = ++i + ++i; это

                  i=i+2;//двойной инкремент
                  i=i+i;//уже по 7


                  Итого i=14.
                  А i=i++ + i++; выдаст 10, если не ошибаюсь, по аналогичной схеме: сначала всё просчитать а потом уж инкрементить. т.е. си отличается ровно на максимализм: либо всё сначала либо всё потом, без промежуточных вариантов.

                  В php и java ситуация иная: там инкременты происходят там где должны — непосредственно в операции. И мы получаем (при том же i=5):
                  i=i++ + i++ = 11
                  или
                  i=++i + ++i = 13
                    0
                    Не все компиляторы C поступают так, но многие. Просто увеличить на 2 быстрее, чем два раза на один, потому уважающий себя оптимизирующий компилятор не приминёт данным ему правом воспользоваться. Но есть и неоптимизирующие компиляторы и даже интерпретаторы - хотя это экзотика, конечно...
                0
                как раз пробелы в выражении очени важны, можно переписать выражение так
                (++i) + (++i)
                  0
                  Пробелы - whitespace, они не учитываются
                    +1
                    ISO/IEC 9899:1999 §6.4.1.3:
                    Preprocessing tokens can be separated by white space; this consists of comments (described later), or white-space characters (space, horizontal tab, new-line, vertical tab, and form-feed), or both. As described in 6.10, in certain circumstances during translation phase 4, white space (or the absence thereof) serves as more than preprocessing token separation. White space may appear within a preprocessing token only as part of a header name or between the quotation characters in a character constant or string literal.

                    Дальше там объясняется почему x+++++y - это не то же самое что x ++ + ++ y и прочее. C - это не Fortran 66...
                • НЛО прилетело и опубликовало эту надпись здесь
                    0
                    "правильный" результат можно получить расставив скобки в выражении правильно, - так как задумывает программист.
                      0
                      В данном случае никакое количество скобок результата не изменит...
                    0
                    С++ предварительно компилирует код! Создается переменная i, с которой и производятся все операции, и даже промежуточные. Вначале выполняет ++i для первого слагаемого (i=5+1=6), затем для второго ++i (i=6+1=7). В итоге получаем переменную i равную 7. И для всего выражения i=7+7=14
                      0
                      Вы меня опередили и по времени и по краткости изложения. Плюсик вам. =)
                      +1
                      а зачем такие выражения i = ++i + ++i; ?

                      давайте тогда писать на BrainFuck
                        0
                        Ретрище...
                        Оба результата правильные для своих языков.
                        Разъяснения в документации
                          0
                          "Ретрище"?
                            0
                            Это типа "ретро" в степени преувеличения? :)
                              –1
                              Это производное от слово "боянище" :)
                            +1
                            При написании кода следует избегать таких неоднозначных конструкций. Если только вы не хакер и/или не тащитесь от того, что ваш код невозможно разобрать, понять, поддерживать.

                            ЗЫЖ Ну есть еще, конечно, вариант оптимизации. Но его, как я разумею, здесь не рассматривают.
                              0
                              однозначно. если человек при работе в команде программистов пишет код, который другим приходится расшифровывать, то за это по заслугам наказывают
                              0
                              Я тоже думая, что в Си это зависит от компилятора. От конкретной реализации.

                              Но вообще вариант 14 правильнее. Операция инкремента имеет наиболее высокий приоритет. Она будет выполнена два раза в процессе вычисления выражения. И только потом переменная i будет сложена с собой (не с собой "в прошлом", а с собой сейчас - и это правильно). И результат присвоен ей же.

                              Так что 14 - логичнее как минимум.
                                0
                                На особо умном RISC'е может и 6 получиться (хотя скорее всего всё-таки 7).
                                0
                                Такой код недопустим.

                                Во-первых, потому что результаты его выполнения могут быть неопределёнными в языке (лень лезть в определение С, скорее всего, там сказано, что порядок выполнения оперендов в a+b "undefined"; как в остальных наследниках С - надо тоже смотреть, в любом случае см. дальше).

                                Во-вторых, и это главное, потому что такая конструкция ставит в тупик читающего код.
                                  0
                                  Именно потому что "такая конструкция ставит в тупик читающего код" - такими дебилизмами полны тесты для соискателей на должность Си-программиста во всякие псевдонавороченные софтовые конторы. А-ля "фокус-покус ведет себя не так как выглядит". По-русски говоря - подъебка.
                                  Многие почему-то думают что классный программист должен идеально эмулировать работу препроцессора и компилятора, причем конкретной и любимой нанимателем фирмы.
                                  0
                                  если мне память не изменяет(хотя я и не уверен в этом =) ) ++i это означает что некоторое число i увеличивается на еденицу (это в "си") . Судя по моим вычислениям должно получиться если i=5, то ответ 12 .Я такого рода вычисления видел в последний раз лет пять назад, так что возможно я и неправ. =))))))
                                    +3
                                    Пациент:
                                    - Доктор, я когда делаю так (человек одной рукой пытается достать себе до лопатки, второй тянется к пятке левой ноги и, при этом, встает на носочек правой ноги) у меня вот тут болит. Доктор, что мне делать?
                                    Врач:
                                    - Не делайте так!
                                      0
                                      класс :))))
                                      +1
                                      Что только люди не делают, лишь бы не читать доки. :)

                                      Итак, правильный ответ: в C/C++ значение этого выражения не определено. Например, в C99 об этом сказано в параграфе 6.5:

                                      2 Between the previous and next sequence point an object shall have its stored value
                                      modified at most once by the evaluation of an expression. Furthermore, the prior value
                                      shall be read only to determine the value to be stored.


                                      В переводе на русский это означает, что неопределенными являются все выражения типа (sequence point у оператора присваивания только одна!):

                                      i = ++i + 1;
                                      a[i++] = i;


                                      Соответственно, вы можете получить абсолютно произвольный результат как на разных компиляторах, так и на одном и том же компиляторе с разными ключами оптимизации. :)
                                        0
                                        РЕТРО! :) Всё зависит от компилятора(интерпритатора). По логике правилен вариант при котором ответ равен 14.
                                          0
                                          sequence point очень занятная тема, но к данному примеру она не имеет отношения.
                                          Тут значение имеет то что получается в результате операции.
                                          В c++ результатом операции ++i является само i, а в java результатом является значние, но не сама переменная. И в вопрос можно сформулировать так: почему приняты настолько разные решения?
                                          Этот конкретный пример врятли напишет в своем коде уважающий себя программист, но, нарпимер, когдато я думал что есть разница между такими вот выражениями:
                                          for (int i=0; i for (int i=0; i length; i++)
                                          и в такое заблуждение меня ввел еще университетский курс и всякого рода книжечки. А ведь выполнение ++i или i++ не влияеть на последовательность и количество самого цикла.
                                          Иногда весьма полезно понимать что на что может влиять.
                                            0
                                            (исправленный код)
                                            for (int i=0; i<length; ++i)
                                            for (int i=0; i<length; i++)
                                          0
                                          И еще вопрос. Если эта тема такой большой боян, и все про все уже знают, тогда почему в обсуждении так много разных мнений и неразберихи? Соответственно я не пойму зачем портить автору харизму, не нравится не читайте.

                                          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                          Самое читаемое