И снова ++x + ++x !!!

Тема в разделе "LANGS.C", создана пользователем _DEN_, 11 май 2007.

  1. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    MSVC 8.0

    Код (Text):
    1. int plus(int a, int b)
    2. {
    3.     return a + b;
    4. }
    5.  
    6. int main()
    7. {
    8.     int x = 0;
    9.  
    10.     x = plus(++x, ++x);
    11.  
    12.     std::cout << x;
    13.  
    14.     return 0;
    15. }
    На экране "4". Должно быть "3". Сначала, корда я их просто оператором складывал, я подумал что для операторов, работающих со встроенными типами, могут быть оговорки в стандарте. Но когда то же самое оказалось для функции, то это уже бред.

    У кого что такая штука напечатает?
     
  2. green

    green New Member

    Публикаций:
    0
    _DEN_
    Порядок вычисления аргументов ф-ций (а также большинства операторов) не определён. Так что компилятор волен выбирать наиболее оптимальный способ, исходя из предположения о независимости результата от порядка вычисления.
    Теоретически, он может для вычисления каждого аргумента запускать отдельный поток. :)
     
  3. CodeTao

    CodeTao Евгений

    Публикаций:
    0
    Я уже про такое слышал. Вроде где-то в стандарте оговаривается, что поведение компилятора не предсказуемое при использовании ин(де)крементирующих операциях в параметрах функции, то бишь это на усмотрение разработчиков компиляторов. В принципе результат правельный, если учитывать что значение аргументов вычисляется до помещения их в стек.
     
  4. Cr4sh

    Cr4sh New Member

    Публикаций:
    0
    >> Должно быть "3"
    почему? машинный код в любом случае будет сгенерён таким образом, что операции инкремента выполнятся до того, как управление получит ф-ция plus
     
  5. RedLord

    RedLord Member

    Публикаций:
    0
    _DEN_
    Comeau 4.3.9 выдал 3
     
  6. RedLord

    RedLord Member

    Публикаций:
    0
    _DEN_

    5.2.2 :

    The order of evaluation of arguments is unspecified. All side effects of argument expression evaluations
    take effect before the function is entered. The order of evaluation of the postfix expression and the argument
    expression list is unspecified.
     
  7. n0name

    n0name New Member

    Публикаций:
    0
    bash.org.ru :derisive:
     
  8. EvilsInterrupt

    EvilsInterrupt Постигающий азы дзена

    Публикаций:
    0
    n0name
    ГЫ )))
    Почему 14, я так и не понял (
    Первое ++и дает 6
    Второе ++и дает 7
    ну и 6 + 7 дает 13
    Почему 14 ?

    Глянул в дизасм:
    Код (Text):
    1. 7:        i = ++i + ++i;
    2. 0040155F   mov         eax,dword ptr [ebp-4]
    3. 00401562   add         eax,1
    4. 00401565   mov         dword ptr [ebp-4],eax
    5. 00401568   mov         ecx,dword ptr [ebp-4]
    6. 0040156B   add         ecx,1
    7. 0040156E   mov         dword ptr [ebp-4],ecx
    8. 00401571   mov         edx,dword ptr [ebp-4]
    9. 00401574   add         edx,dword ptr [ebp-4]
    10. 00401577   mov         dword ptr [ebp-4],edx
    почему такое? Этож неправильно! Почему он должен был складывать eax, ecx. Получается что ecx + ecx! MS VC++ 6.0
     
  9. Ultrin Faern

    Ultrin Faern New Member

    Публикаций:
    0
    Я бы на месте компилятора вообще упростил выражение -
    i = ++(++i)<<1 :)))
     
  10. maxdiver

    maxdiver Max

    Публикаций:
    0
    _DEN_
    В Стандарте даже специальный пример дан:
    Код (Text):
    1. i = ++i + 1;  // the behavior is unspecified
     
  11. Mental_Mirror

    Mental_Mirror New Member

    Публикаций:
    0
    maxdiver
    Дайте плиз стандарт.
     
  12. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Ну е-мое...

    При чем тут порядок вычисления аргументов? Во-первых, я знаю что он не определен. Во-вторых, в моем примере он совершенно не влияет на результат и к сути вопроса вообще никакого отношения не имеет.

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

    plus(++i, ++i);

    Для того чтобы вызвать функцию, надо вычислить ее аргументы. Аргументы вычисляются последовательно. Т.к. в моем примере последовательность на результат не влияет, то будем считать, что они вычисляются по порядку.

    Сначала первый. plus(++i, ...); ++i дает 1. Все. Первый параметр функции вычеслен. Он равен 1 и больше меняться не будет. Готово. Идем дальше.
    Второй параметр. plus(..., ++i); i уже равно 1, поэтому ++i равно 2. Второй параметр вычеслен. Он равен 2 и меняться тоже не будет.
    Все, аргумены готовы, известны их значения, можно вызывать функцию.

    plus(1, 2);

    То, что студия считает что резутьтатом будет 4, говорит о том, что она думает, что ++i должно выполниться еще ДО того, как началось вычисление аргументов функции. На сколько я понимаю, это НЕПРАВИЛЬНО, т.к. любой оператор начинает свою работу не раньше того момента, как до него дошло управление.


    RedLord

    Согласен с Comeau.


    maxdiver

    Ты уверен что там префиксный, а не постфиксный?
     
  13. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    EvilsInterrupt

    С каких пор мы обращаемся к компиляторам по вопросам стандарта? ;)
     
  14. green

    green New Member

    Публикаций:
    0
    _DEN_
    Стандарт не обязывает компилятор вычислять аргументы последовательно. Он может вычислять их даже одновременно.
    Процесс вычисления аргумента состоит из
    а. инкремента x
    б. передачи х в ф-цию (записи х в стек).

    В твоём случае компилятор VC8, вероятно, вычисляет так (1 - первый арг., 2 - второй арг.):
    1а, 2а, 1б, 2б.
    В результате вызывается plus(2, 2).

    А Comeau так:
    1а, 1б, 2а, 2б
    Результат: plus(1, 2).

    В данном случае это показывает, что компилятор VC8 использует больше возможностей для оптимизации, чем Comeau.

    ---
    Стандарт лишь регламентирует, что аргументы должны быть вычислены до выполнения кода ф-ции.
     
  15. maxdiver

    maxdiver Max

    Публикаций:
    0
    _DEN_
    Уверен. Потому что я сделал копи-паст :)
    Впрочем, green уже всё объяснил. И префиксный, и постфиксный операторы могут дать побочные эффекты.
     
  16. maxdiver

    maxdiver Max

    Публикаций:
    0
    Mental_Mirror
    К сожалению закачать никуда не могу - размер 2.4 Мб, и связь обрывается.
    Погугли - ключевые слова: " C++ International Standard 14882:2003 " (у меня такой версии).
     
  17. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    maxdiver

    Я не понимаю почему это UB.

    green

    Откуда уверенность в том, что вычисление конкретного аргумента не обязано быть атомарным?
     
  18. n0name

    n0name New Member

    Публикаций:
    0
    iso 9899: 1999 круче ;)
    Там тоже написано что не предусматривается поведения в таких ситуациях.
     
  19. green

    green New Member

    Публикаций:
    0
    _DEN_
    От того, что стандарт не обязывает его быть атомарным. :)
     
  20. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    green

    Об этом сказано? :)

    Почему i = ++i + 1; - UB ? Единичка-то она и в Африке единичка.