Почему MISRA-C:2004 выдает здесь ошибку?

Кажется, я продолжаю получать ошибки правил 10.1 и 10.3 MISRA-C:2004 для назначения lShift в следующем фрагменте и не вижу, что еще можно сделать, чтобы удовлетворить требование... почему я все еще получаю ошибку?

#define ADC_INTSELxNy_LOG2_NUMBITS_PER_REG 3U
#define ADC_INTSELxNy_NUMBITS_PER_REG 8U
void foo (const bar_e intNumber) {
    uint_least8_t lShift = (uint_least8_t)(ADC_INTSELxNy_NUMBITS_PER_REG - (((((uint_least8_t)intNumber) + 1U) & 0x1U) << ADC_INTSELxNy_LOG2_NUMBITS_PER_REG));
    //...
}

person Toby    schedule 05.01.2015    source источник
comment
Что такое правила 10.1 и 10.3?   -  person mafso    schedule 05.01.2015
comment
10.1: Значение выражения целочисленного типа не должно неявно преобразовываться в другой базовый тип, если А) это не преобразование в более широкий целочисленный тип того же знака, или В) выражение является сложным, или С) выражение не является константой и является аргументом функции, или D) выражение не является константой и является возвращаемым выражением.   -  person Toby    schedule 05.01.2015
comment
10.3: Значение сложного выражения целочисленного типа может быть приведено только к более узкому типу и тому же знаку, что и базовый тип выражения.   -  person Toby    schedule 05.01.2015
comment
хотя 10.3, похоже, уже ушел, несмотря на то, что я ничего не менял...   -  person Toby    schedule 05.01.2015
comment
Что такое bar_e? И хотя мне не ясно, что здесь должен означать базовый тип, A) кажется нарушенным, потому что uint_least8_t (в большинстве систем) повышен до int. Возможно, изменение приведения на (unsigned) и маскирование с помощью 0xff (что, по-видимому, является вашим намерением, а не маскирование с помощью (unit_least8_t)-1 в любом случае) делает это. Однако я не знаком с MISRA (и не согласен с большинством правил, которые я видел до сих пор).   -  person mafso    schedule 05.01.2015


Ответы (1)


Эта строка представляет собой нечитаемый беспорядок. Подумайте о том, чтобы разделить его, чтобы повысить читабельность. В зависимости от ширины int в вашей системе код будет выглядеть по-разному. Код ниже предполагает 32-битные целые числа.

uint8_t        bit      = (uint8_t)( ((uint32_t)intNumber + 1U) & 0x1U );
uint32_t       lShift32 = ((uint32_t)bit << ADC_INTSELxNy_LOG2_NUMBITS_PER_REG);
uint_least8_t  lShift8  = (uint_least8_t)((uint32_t)ADC_INTSELxNy_NUMBITS_PER_REG - lShift);

Теперь, что касается причины, по которой вы получили ошибки, правила 10.1 и 10.3 касаются неявного повышения целочисленного типа. Если вы разделите код, как я сделал выше, вы меньше запутаетесь в том, что такое «основной тип» каждого подвыражения. Что вы сделали неправильно, так это добавили приведение к базовому типу перед операцией, что мало что дает. Это нужно делать после каждой операции.

Операция + требует явного приведения к базовому типу после операции +, то же самое с операцией & и операцией сдвига. Недостаточно просто привести все к базовому типу в конце, вы должны рассматривать каждое подвыражение отдельно.

Чтобы объяснить мой код выше:

Первая строка имеет явное приведение к uint32_t, чтобы гарантировать, что intNumber имеет тот же тип, что и 1U. Таким образом, нет неявного преобразования подвыражения intNumber + 1U, и это более широкий тип с той же подписью, что и базовый тип uint8_t (что означает, что он безопасен). Результат сложения имеет тип unsigned int. Опять же, unsigned int & unsigned int не дает неявного преобразования. И, наконец, результат приводится к uint8_t, чтобы удовлетворить ряду правил MISRA. Остальная часть кода выполняется таким же образом.

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

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

person Lundin    schedule 08.01.2015
comment
Это работает нормально, пока я не добавлю последний шаг, вычитание (которое, возможно, вы пропустили + с использованием 16-битных целых чисел) uint_least8_t lshift8 = (uint_least8_t)(ADC_INTSELxNy_NUMBITS_PER_REG - (uint_least8_t)lShift16);. Может быть, я все еще не понимаю продвижение по службе? - person Toby; 14.01.2015
comment
Ах, должно быть uint_least8_t lShift = (uint_least8_t)((uint16_t)ADC_INTSELxNy_NUMBITS_PER_REG - .... Та - person Toby; 14.01.2015
comment
@Toby Упс, да, я пропустил эту часть. Позвольте мне отредактировать сообщение. Действительно, вам нужно явное приведение, если только ADC_INTSELxNy_NUMBITS_PER_REG уже не является достаточно большим типом. - person Lundin; 15.01.2015