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

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

  1. PaCHER

    PaCHER New Member

    Публикаций:
    0
    Регистрация:
    25 мар 2006
    Сообщения:
    852
    _DEN_
    Ты асм листинг смотрел опираций в #8 посте, что тебе еще не понятно.
     
  2. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    PaCHER

    Например мне непонятно почему такие как ты считают, что asm-листинг может быть каким-то аргументом.
     
  3. RedLord

    RedLord Member

    Публикаций:
    0
    Регистрация:
    23 июн 2005
    Сообщения:
    183
    Адрес:
    Ukraine
    _DEN_
    похоже, что тройка получается.
    http://c-faq.com/expr/seqpoints.html
     
  4. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    _DEN_
    "Что не запрещено- можно" :derisive:
    Компилятор вправе делать, что угодно, если это не противоречит требованиям стандарта. IMHO.
    Здесь я тоже толком не понимаю... Подумаю.
     
  5. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    green

    ну в стандарте например напрямую не сказано что чтение из указателя со значением 897435453 это UB :derisive: Есть более общая оговорка - чтение из невалидного указателя это UB. Напрямую может быть и не сказано, что вычисление аргумента должно быть атомарно.
     
  6. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    _DEN_
    Я не встречал в стандарте более общего утверждения, из которого бы следовало, как частный случай, что вычисление аргумента должно быть атомарно. Посему претензий к компилятору не имею. :derisive:
    Более того, мне нравится агрессивная, изобретательная оптимизация VC - не в пример другим компиляторам, включая Intel.
     
  7. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    green

    ...которая не позволяет писать кросс-палформенные решения :-D
     
  8. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    _DEN_
    Не понимаю, какое отношение имеет оптимизация к кросплатформенности... Или ты намекаешь, что VC оптимизирует в ущерб соблюдению стандарта ? Можешь привести пример ?
    Согласен, что VC поддерживает стандарт не полностью, но, AFAIK, вовсе не из-за ошибок оптимизатора. Кроме того, не поддерживаются совсем уж экзотические фичи, без которых вполне можно обойтись.
     
  9. maxdiver

    maxdiver Max

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    308
    Адрес:
    Саратов
    В Стандарте (если я правильно перевел это заумное предложение ;) ) написано, что если переменная в одном выражении изменяется дважды, то результат уже неопределён. Единственное исключение, когда результат точно определён, это при применении запятой-оператора.

    Насчёт цитируемого примера. Видимо, это всего лишь демонстрация правила: раз переменная изменяется дважды, то результат не определён. Хотя на всех современных компиляторах он окажется правильным (ИМХО).
    Да наверное, и не получится разумно описать все возможные варианты, когда выражение корректно, а когда нет. Проще все объявить неопределёнными :)

    На всякий случай приведу весь абзац из Стандарта:
     
  10. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    i = 7, i++, i++; // i becomes 9

    эээээээээээээээээээээ...............

    Почему тогда

    return 1, 2, 3, 4, 5; // вернет 5 ???
     
  11. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    _DEN_

    А что здесь странного? Для оператора comma, как и && и || порядок вычисления аргументов определён Стандартом.
     
  12. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    green

    Эти два примера противорячат друг другу.

    i = 7, i++, i++; // i becomes 9

    говорит о том, что происходит следующее:

    ((i = 7), i++), i++);

    return 1, 2, 3, 4, 5; // вернет 5

    говорит о том, что это эквивалент

    return ((((1, 2), 3), 4), 5);

    А не

    (((((return 1), 2), 3), 4), 5);
     
  13. CodeTao

    CodeTao Евгений

    Публикаций:
    0
    Регистрация:
    31 окт 2006
    Сообщения:
    177
    Адрес:
    штаты
    Там точно в конце единица, а не i?
     
  14. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    CodeTao

    Вот и я думаю! Не пора ли баг репорт Александреске писать? :))
     
  15. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    _DEN_
    приоритет у оператора присваивания выше, чем у оператора комма. А у "оператора" return - ниже, он хавает все до ;
     
  16. Nouzui

    Nouzui New Member

    Публикаций:
    0
    Регистрация:
    17 ноя 2006
    Сообщения:
    856
    у return вообще нет никакого приоритета
    if, else, goto, return итд называются операторами, так же, как и +, -, *, / ...
    но не надо их путать

    CodeTao
    точно. поясняю - стандарт оставляет разработчикам компиляторов широкие возможности для оптимизации, стараясь по-возможности не ограничивать их правилами, определяющими последовательность выполнения операций. в частности, он оставляет неопределенными результаты выражений, в которых какие-либо переменные между двумя "sequence points" изменяются больше, чем один раз ("Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression").
    Поэтому результат выражения i= ++i + 1; неопределен. не из-за каких-то особенностей опреаторов, а просто из принципа
    другое дело, что я тоже с трудом представляю себе оптимизацию, при которой результат (с учетом того, что преинкремент дает ссылочное значение) будет отличаться от <изначальное i>+2.

    вторая вещь, которую следует понимать, это примечание к цитате, которую привел maxdiver:
    так вот, слдует помнить, что операторы не "должны выполняться в порядке их следования". приоритет операций, так же, так и правила ассоциативности, задает только правила грамматического разбора предложений: a+b*c понимается именно как a+(b*c), а не (a+b)*c, и только. оно не предписывает выполнять сначала умножение, и, затем, сложение. если b*c уже вычислялось раньше и значения операндов с тех поря явно не изменялись (в частности, не использовалось взятите их адресов с передачей в какую-нибудь функцию), компилятор может запомнить старый результат и использовать его в этом выражении (исключение составляют случаи, когда b или c объявлены как volatile).
    точно так же, выражение (a+b)*c говорит только о том, что что математически результат должен соответствовать сначала сложению, а затем ужножению, но не запрещает компилятору вычислять это выражение как-нибудь вот так: a*c+b*c
    естественно, все вышесказанное относится исключительно к базовым типам, то есть, если в предыдущем примере a, b и c являлись бы объектами, то выражение (a+b)*c однозначно превратится в вызвы:
    tmp= operator+(a, b)
    result= operator*(tmp, c)

    теперь что касается топика: преинкрементный ++ возвращает l-value
    то есть вызов func(++i, ++i) фактически можно рассматривать так:
    ++i;
    ++i;
    func(i, i);
    или так:
    ++i;
    func(i,<еще раз ++i;> i);
    я не знаю точно, требует ли стандарт от компилятора учитывать в данном случае, что i изменяется дважды, то есть обязан ли результат быть равен именно 4, а не 3. насколько я понимаю - нет, стандарт не определяет поведение компилятора в данном случае
    кстати, фактически запись func(++i, ++i) должна быть эквивалентна func(i+=1, i+=1);
     
  17. pluton

    pluton New Member

    Публикаций:
    0
    Регистрация:
    8 фев 2007
    Сообщения:
    66
    Адрес:
    Odessa
    Проверил этот код в C# 2.0:
    Код (Text):
    1. using System;
    2. using System.Collections.Generic;
    3. using System.Text;
    4.  
    5. namespace plusplus
    6. {
    7.   class Program
    8.   {
    9.     static int func(int a, int b)
    10.     {
    11.       return a + b;
    12.     }
    13.  
    14.     static void Main(string[] args)
    15.     {
    16.       int i = 0;
    17.       int x = func(++i, ++i);
    18.       Console.WriteLine(x);
    19.       Console.ReadKey(true);
    20.     }
    21.   }
    22. }
    Возвращает "3"
     
  18. Nouzui

    Nouzui New Member

    Публикаций:
    0
    Регистрация:
    17 ноя 2006
    Сообщения:
    856
    # все-таки не C, в нем и просто ++x + ++x = 3
     
  19. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    pluton

    Бу-га-го!!! :)))) Ты еще в кларионе проверь)))))))))
     
  20. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    green

    Это вроде как все объясняет. Кроме того, почему все же i = ++i + 1 это UB.

    Огромный пост Nouzui к сожалению ничего не прояснил. т.к. свобода для оптимизации не должна противоречить стандарту, а если приведенный пример это UB, то от стандарта необходимо отойти. Другого способа я пока не вижу.