1. Си / Говнокод #21607

    −51

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    void iseq(int a, int b){ assert(a==b); }
    void ismt(int a, int b){ assert(a+1==b); }
    
    int main(int argc, char **argv){
    
    	{ int j=100, *jp; jp=&argc; iseq(j++, j); assert(j==101); } //100, 100
    	{ int j=100, *jp; iseq(j++, j); jp=&j; assert(j==101); } //100, 100
    	{ int j=100, *jp; iseq(j++, j); assert(&j && j==101); } //100, 100
    	{ int j=100, *jp; ismt(j++, j); assert(j==101); } //100, 100
    	
    	{ int j=100, *jp; jp=&j; printf("\n%d, %d\n", j++, j); assert(j==101); } //100, 100
    	{ int j=100, *jp; printf("%d, %d\n", j++, j); jp=&j; assert(j==101); } //100, 100
    	{ int j=100, *jp; printf("%d, %d\n", j++, j); assert(&j && j==101); } //100, 100
    	{ int j=100; printf("%d, %d\n", j++, j); assert(j==101); } //100, 101
    	
    	{ int j=100, *jp; jp=&j; printf("\n%d, %d\n", ++j, j); assert(j==101); } //101, 100
    	{ int j=100, *jp; printf("%d, %d\n", ++j, j); jp=&j; assert(j==101); } //101, 100
    	{ int j=100; printf("%d, %d\n", ++j, j); assert(j==101); } //101, 101
    	 
    	return 0;
    }

    Кто нибудь знает почему ЭТО работает так? Проверял на нескольких компиляторах везде такой эффект.

    Запостил: rst256, 31 Октября 2016

    Комментарии (25) RSS

    • судя по всему автор не знал про порядок вычисления аргументов, тот случай, когда лучше макросы, чем функции
      Ответить
      • Автор не знал что операция взятия адреса над переменной в не зависимости была она произведена до вызова функции или после нее будет оказывать такой интересный эффект.на порядок вычисления ее аргументов.
        Ответить
        • > операция взятия адреса
          Когда адрес переменной не нужен - конпелятор может засунуть переменную в регистр и даже не выделять под неё память. Когда берёшь адрес - волей-неволей приходится юзать настоящую переменную. Вот тебе и другие оптимизации с другим поведением.

          З.Ы. И если ты поюзал что-то, что в стандарте обозначено как undefined (а порядок вычисления аргументов как раз таки не определён) - на результат даже фаза луны влиять будет, не то что взятие адреса...
          Ответить
    • Аргументы вычисляются в неопределенной последовательности. Вычисления даже могут пересекаться. Поэтому ответ такой: так работает, потому что так удобнее компилятору.
      Ответить
      • Пересекаться - это когда выгодно переюзать результат промежуточных вычислений?
        Ответить
        • Хз. Может компилятор решит переупорядочить вычисления, чтобы лучше загрузить конвейер.

          Ты знал, что make_shared сделали не только для оптимизации пирфоманса? Вызов
          foo(std::shared_ptr<int>(new 5), bar());

          может течь, если bar() бросает исключения. Потому что код может выполняться в последовательности 1) new 5; 2) bar(); 3) std::shared_ptr(...).
          Ответить
          • Понятно.
            Но при чем здесь shared_ptr? я не знаю что это
            Ответа foo(koko(bar()), baz()) вполне достаточно.
            Ответить
            • привел жизненый пример
              Ответить
            • > вполне достаточно
              не совсем
              память выделенная на стеке, освободится в том числе в случае исключения, но в примере с shared_ptr - память выделяется через new в куче, её нужно освобождать через delete, это должен сделать сам shared_ptr, но из-за исключения до него дело не дойдёт.
              Ответить
              • проблема конкретно shared_ptr немного в другом. Если создавать его через new, происходит два выделения памяти (одно под нужды shared_ptr), и в случае удачного первого и неудачного второго память утекает. А для базового примера утечки с исключением в конструкторе достаточно foo(new A, new B)
                Ответить
    • И что это за несколько компиляторов, на которых ты проверял? 15 студия и 13?

      http://coliru.stacked-crooked.com/a/3b10ae5964ab8cc2
      http://coliru.stacked-crooked.com/a/3251602c5a8a92e8

      Обрати внимание, как шланг без всяких флагов сообщил, что в коде баг.
      Ответить
      • tcc 0.9.26 и gcc 4.9.4,
        У gcc как оказалось это предупреждение по умолчанию выключено. С "-Wall" он выдал такие же предупреждения что и clang.
        Ответить
    • > почему ?
      g: sequence point
      Ответить
    • Постинкремент/постдекремент в правой части выражений лучше вообще не использовать, потому что увеличение/уменьшение значения откладывается на неопределённое время, зависящее от компилятора и от флагов оптимизации. Т. е. полагаться на значение переменной внутри того же выражения, в котором использовали постинкремент, нельзя. А вот после так называемой точки следования (о которой упомянул 4e1) новое значение уже можно использовать.
      Ответить
      • В сишке точки следования еще не выпилили? В 11 плюсах вот выпилили, и запилили какую-то другую дичь.
        Ответить
        • Собственно точки следования были жестче. Sequenced-before даже больше компилятору позволяет. Правда наткнуться на это можно разве что в многопоточных приложениях.
          Ответить
      • показать все, что скрытоVanished
        Ответить
    • Добро пожаловать в клуб "++i + ++i".
      А ведь уже несколько поколений сишников и крестовиков сталкиваются с подобными UB! Так и представляю картину - камин, кресло-качалка, в нём сидит дедушка и внуку рассказывает: "А вот как-то кодил я на плюсах, да угораздило-ж меня два инкремента в одну точку следования всунуть!..".
      Ответить
      • Есть ещё клуб «i++ + i».

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

        Преинкремент по идее должен быть менее коварным, чем постинкремент, но оптимизация может помочь испортить и его.
        Ответить
        • Шо то UB, шо это UB. Вот это обе UB такие, шо я бля его диск в компайл тайме форматировал.
          Ответить
    • показать все, что скрытоБорманд, задыхась от жадности, полирует купол моего храма.
      Ответить

    Добавить комментарий