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

    −2

    1. 1
    2. 2
    3. 3
    4. 4
    static volatile stm32f4_usart *usart_get_regs(const console_tbl *ct)
    {
      return (stm32f4_usart *) ct->ulCtrlPort1;
    }

    А если будет замест volatile - inline, возможен вариант, что компилятор выкинет эту функцию?

    Запостил: MiD, 07 Ноября 2016

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

    • показать все, что скрытоУ какой национальности самый большой процент широких анусов?
      Ответить
    • volatile же не к функции относится, а к возвращаемому типу...

      volatile stm32f4_usart *
      Ответить
      • ам...т.е. чуваки подумали, что указатель типа stm32f4_usart может быть выкинут компилятором? И что тогда, функция которая должна что-то возвращать, не будет возвращать..бред какой-то...

        з.ы. взято отседова:
        https://devel.rtems.org/browser/rtems/c/src/lib/libbsp/arm/stm32f4/console/usart.c?rev=1485a58ce30c4ced71446976036f 03a5c32f451d
        Ответить
        • Не, они хотели чтобы операции с полями этой структуры (а это memory mapped порты железки) не оптимизировались:
          stm32f4_usart *foo = usart_get_regs(...);
          
          foo->some_reg = 5; // конпелятор с чистой совестью выкинет эту строку
          foo->some_reg = 42; // потому что старое значение затёрли записью 42
          
          foo->some_reg = 5;
          r = foo->some_reg; // конпелятор тупо положит в r пятёрку и не будет перечитывать some_reg
          С volatile эти обращения будут работать так, как задумано.
          Ответить
          • возможно херню спрошу, правильно ли я понимаю. У них там встречаются такие вот дела:

            union {
            struct {
            uint32_t val1 :1;
            uint32_t val2 :5;
            uint32_t val3 :8;
            ....
            } fields;
            uint32_t reg;
            };

            где val1, val2...valN - это битовые поля внутри регистра, заданной длины. Если я буду, конфигурирую регистр, через битовые поля и не использую volatile, очень велика вероятность, что компилятор может каким то образом всё мне поломать? А если может, то как, например?)
            Ответить
            • А, всё, догнал. Пора идти домой, туплю:)
              Ответить
            • > то как, например
              Может склеить несколько обращений к битовым полям в одну операцию над целым регистром. Обычно на это насрать, только быстрее работать будет... Но если в даташите, например, написано "заполните все биты кроме enable, а затем установите enable", то может получиться факап.
              Ответить
            • Может в С89 или С++. Не может в С99 или С11.
              Например может сломать так:
              this_union foo;
              foo.reg = 0;
              foo.fields.val1 = 1;
              foo.fields.val1 = 2;
              foo.fields.val1 = 3;
              printf("%d", foo.reg);
              // Печатает 0. А что, ложил в reg ты 0, что ещё ожидаешь увидеть?

              Теоретически индеец ещё может поломать. И то что положение битовых полей в структуре не определено ЕМНИП.
              Ответить
              • Ужас то какой... А есть компиляторы, которые реально так делают?

                Гцц, например, явно оговаривал, что можно такие махинации через юнион гонять...
                Ответить
                • Вряд ли. Гцц разрешал это с незапамятных времён в С, С++ ведёт себя как можно ближе к С. Шланг копирует поведение гцц. MS следует за лидерами вроде как.

                  Реально можно напороться на проблемы если у тебя есть указатель на поле юниона. Большинство компиляторов теперь следуют strict-aliasing и запись/чтение несовпадающих типов может не работать.
                  Ответить
                  • Ну про указатель то понятно. Но тут у ОП'а, как я понял, совсем другой кейс - этот union помещается прямо поверх memory mapped порта некой железки и код через него оперирует с нужными битами. Т.е. это не ради каста, а ради удобства, чтобы сдвиги и логику не писать.
                    Ответить
                    • В таком случае, как с любыми memory mapped устройствами, volatile нужно таки поставить.
                      Ответить
                      • Ну да, иначе первое же ожидание какого-нибудь ready бита повешает всё к хуям :)
                        Ответить
                        • А если объект уже проинициализирован как volatile, нужно ли указатель на него тоже volatile делать?
                          Ответить
                          • Сам указатель нет, на что указывает — да. Хотя без volatile компилятор не даст сделать, будет ругаться на отбрасывание cv-qualifiers.
                            Ответить
              • Ну индеец да положение полей всё-таки implementation defined, не UB. Т.е. под конкретный компилятор/семейство чипов можно запинать. А больше эмбедщикам и не надо.
                Ответить
                • А вот извлечение из юниона не того, что положили, всё же UB. Because fuck you, that's why.
                  Ответить
                  • показать все, что скрытоVanished
                    Ответить
                  • But gcc (at least) explicitely specifies behavior of this pattern :3

                    The practice of reading from a different union member than the one most recently written to (called “type-punning”) is common. Even with -fstrict-aliasing, type-punning is allowed, provided the memory is accessed through the union type.

                    https://gcc.gnu.org/onlinedocs/gcc-4.9.2/gcc/Optimize-Options.html
                    Ответить

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