Действительно ли все эти приведения типа C необходимы для побитовых операций с регистрами?

Я нахожу стиль кодирования в STM32F0 (микроконтроллер ARM Cortex-M0) SPL (стандартная периферийная библиотека) излишне многословным. В качестве примера, вот фрагмент кода для настройки контура фазовой автоподстройки частоты для SYSCLK:

/* Select PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;  

Где RCC_CFGR_SWи RCC_CFGR_SW_PLLмакросы для целочисленных литералов уже приведены к uint32_t.

#define RCC_CFGR_SW     ((uint32_t)0x00000003) 
#define RCC_CFGR_SW_PLL ((uint32_t)0x00000002)  

И RCC->CFGRявляется (отображенным в память) экземпляром структуры типа

typedef struct
{
    ...
    __IO uint32_t CFGR; /*!< RCC clock configuration register, Address offset: 0x04 */
    ...  
} RCC_TypeDef;  

Таким образом, результат будет неявно приведен в uint32_tлюбом случае, даже с предупреждением, если произойдет что-то смешное (в отличие от того, что произойдет с явным приведением).


Можно ли исключить эти явные приведения, особенно учитывая, что C99 гарантирует (6.3.1.3), что

  • Когда значение с целочисленным типом преобразуется в другой целочисленный тип, отличный от _Bool, если значение может быть представлено новым типом, оно не изменяется.

Позволяет упростить код до значительно более ясного

//Select the PLL as system clock source
RCC->CFGR &= ~(RCC_CFGR_SW);
RCC->CFGR |= RCC_CFGR_SW_PLL;  

Или это может вызвать непредвиденные побочные эффекты? Я не совсем уверен, и я предполагаю, что люди, которые написали этот код, более опытны в написании встроенного C, чем я...

Я задаю этот вопрос на electronics.stackexchange вместо stackoverflow, поскольку он довольно специфичен для встроенного программирования низкого уровня.

Можете ли вы гарантировать, что результатом всех этих выражений будет uint32_t? 0x00000003 тоже uint32_t? Вы действительно хотите беспокоиться о том, что это так, и думать о том, гарантировано ли это или нет, или вы хотите убедиться, что результат есть, поэтому просто сообщите компилятору, что вы хотите, чтобы он был?
«Я предполагаю, что люди, которые написали этот код, более опытны в написании встроенного C, чем я». Очевидно, у вас еще нет большого опыта работы с ST SPL :D
Я думаю, что stackoverflow будет лучше. Это именно то, с чем имеют дело хардкорные юристы языка C, и с чем они имеют дело с 1989 года, когда были стандартизированы все странные «неявные целочисленные преобразования» препроцессора C + среды выполнения. Я уверен, что вы получите хорошие ответы и здесь.
Взгляните на правила Misra, чтобы понять, зачем нужны все эти приведения.
должен согласиться с @Armandas. и я полностью не согласен с Арсеналом. я довольно хорошо знаю прямой ANSI C, и, если предположить, что это RCC->CFGRтакже uint32_t, то приведения в первых двух утверждениях полностью избыточны. вокруг много паршивых программистов, которые не понимают, что помимо написания работающего кода важно также сделать его кратким, читабельным и простым в сопровождении.
Не только приведения типов, но и круглые скобки в первых двух утверждениях избыточны. Некоторым программистам нравится тратить свое время на повторение очевидного. Не подражайте.
Хотя в этом случае броски кажутся излишними, возможно, кто-то защищался: см. номер 3 на lysator.liu.se/c/ten-commandments.html .

Ответы (1)

Давненько я не тратил время на чтение стандартов C. Но есть ключ из всего того, что может быть полезно, в общем. Я не думаю, что это большая помощь здесь, хотя. Позвольте мне изложить то, что я помню, а затем рассмотреть, есть ли какие-либо дополнительные комментарии. (Однако я не уверен, что здесь стоит искать авторов компиляторов C, и именно они должны знать точные детали.)

Когда C преобразует целое число со знаком в целое число без знака того же физического размера, стандарт требует , чтобы компилятор C выдавал результат без знака, который либо (1) имел бы то же самое эквивалентное значение, означающее в пространстве символов без знака, либо иначе; (2) значение со знаком по модулю 2 б я т с я г е . Такие преобразования гарантируют конкретный математический результат. Тот, который большинство людей ожидает, на самом деле. Однако, когда беззнаковое целое число преобразуется в знаковое целое, опять же того же физического размера, стандарт требует , чтобы , если и только если существует эквивалентное значение, означающее , то это значение должно поддерживаться. Если, однако, беззнаковое значение превышает предел положительного значения, означающего , то стандартного результата вообще не будет. Я полагаю, что компилятор C может генерировать случайную чепуху, если захочет.

Возможно, левая рука не знает, что делает правая в кодировании, которое вы видите. Вы, конечно, можете пойти посмотреть и увидеть очевидное. Но возможно, что те, кто пишет выражения, пытаются защищаться в том смысле, что кто-то может позже переписать константу из того, что раньше было беззнаковым значением, в значение со знаком (или по умолчанию со знаком). (Компиляторам C разрешено или раньше разрешалось делать свой собственный выбор по умолчанию, когда спецификатор signed или unsigned отсутствовал. И если им не разрешалось, некоторые, безусловно, все равно это делали.)

Приведение объектов к неподписанным всегда гарантирует конкретный результат. Так безопаснее использовать. Или когда-то был, когда я читал стандарты много лет назад. На всякий случай кто-то использовал явно или по умолчанию компилятора значение со знаком.

Все это говорит о том, что я не могу вспомнить компилятор C, который делал бы что-то сумасшедшее при преобразовании целого числа без знака в целое число со знаком. В общем, если предположить, что компьютерное оборудование использует обычную запись с дополнением до двух, все они просто делают очевидное и делают их побитово идентичными. Позже меняется только интерпретация. Но это не значит, что кого-то, кто действительно читал стандарты, это должно волновать — они могут решить написать так, как будто существует сумасшедший компилятор C. Просто чтобы доказать, что они читали стандарт.

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