MISRA C: 2004, ошибка со смещением бит - PullRequest
4 голосов
/ 04 февраля 2012

Я использую компилятор IAR Workbench с проверкой MISRA C: 2004.
Фрагмент:

#define UNS_32 unsigned int
UNS_32 arg = 3U;
UNS_32 converted_arg = (UNS_32) arg;
/* Error line --> */ UNS_32 irq_source = (UNS_32)(1U << converted_arg);

Ошибка MISRA: Ошибка [Pm136]: недопустимое явное преобразование из базового типа MISRA "unsigned char" в "unsigned int" (MISRA C 2004, правило 10.3)

Я не вижу unsigned char ни в одном из приведенных выше кодов.

Обсуждение на Почему Мисра выбросила здесь ошибку? обсуждает умножение, которое может иметь другие правила продвижения, чем сдвиг влево.

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

Что здесь на самом деле происходит?

Как мне сделать код, совместимый с MISRA C: 2004?

Редактировать 1:

Изменение строки ошибки на:

UNS_32 irq_source = (UNS_32)((UNS_32) 1U << converted_arg);  

не не исправляет ошибку.

Ответы [ 3 ]

4 голосов
/ 06 февраля 2012

Второй вопрос первый:

Как мне сделать код, совместимый с MISRA C: 2004?

Вы можете написать это в соответствии с MISRA следующим образом:

typedef unsigned int UNS_32;

UNS_32 test(void);
UNS_32 test(void)
{
  UNS_32 original_arg = 3U;
  UNS_32 irq_source = 1UL << original_arg;

  return irq_source;
}

Вернуться к первому вопросу:

Что здесь на самом деле происходит?

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

Одним из ключей к пониманию сообщения об ошибке является концепция базового типа , которая является специфической концепцией MISRA-C. Короче говоря, базовый тип константы - это самый маленький тип, в который она может вписаться В этом случае 1U имеет базовый тип unsigned char, несмотря на то, что он имеет тип языка unsigned int.

Логическое обоснование правила 10.3 состоит в том, чтобы избежать случаев, когда результат операции используется в контексте, который больше, чем части. Стандартным примером этого является умножение, где alpha и beta являются 16-битными типами:

uint32_t res = alpha * beta;

Здесь, если int равен 16 битам, умножение будет выполняться в 16 битах, а результат будет преобразован в 32 бита. С другой стороны, если int равен 32 битам или больше, умножение будет выполняться с большей точностью. Конкретно, это будет отличать результат при умножении, скажем, на 0x4000 и 0x10.

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

Если предполагается использовать 16-битное умножение:

uint16_t tmp = alpha * beta;
uint32_t res = tmp;

С другой стороны, если целью является 32-битное умножение:

UNS_32 res = (UNS_32)alpha * (UNS_32)beta;

Итак, в этом случае выражение 1U << count является потенциальной проблемой. Если converted_arg больше 16 бит, это может привести к проблеме при использовании 16-битных int с. Однако MISRA позволяет вам писать 1UL << count или (UNS_32)((UNS_32)1U << original_arg). Вы упомянули, что в последнем случае средство проверки MISRA выдало ошибку - у меня ее нет, поэтому повторите проверку.

Итак, на мой взгляд, средство проверки MISRA C, которое вы использовали правильно, выявило нарушение правила 10.3.

3 голосов
/ 04 февраля 2012

В C89, который определяют правила MISRA, тип целочисленной константы с суффиксом U является первым из списка "unsigned int, unsigned long int" , в котором его значение может быть представлял. Это означает, что тип 1U должен быть unsigned int.

Определение оператора побитового сдвига указывает, что целочисленные преобразования выполняются для каждого операнда (это не меняет unsigned int), и что тип результата является типом повышенного левого операнда. В этом случае тип результата (1U << converted_arg) поэтому равен unsigned int.

Единственное явное преобразование здесь - приведение этого значения unsigned int к unsigned int, поэтому это должно быть то, о чем предупреждает компилятор - хотя в поле зрения нет unsigned char, что означает, что средство проверки выглядит быть багги.

Технически, однако, это приведение от unsigned int до unsigned int действительно нарушает правило 10.3, которое говорит, что результат «сложного выражения» может быть приведен только к более узкому типу - и приведение к тот же тип явно не приведен к более узкому типу.

В ролях нет необходимости - я бы просто опустил его.

0 голосов
/ 18 октября 2018

В первые дни MISRA программы, к которым он применялся, иногда предназначались для компиляторов, поведение которых не соответствовало еще не опубликованному стандарту C89.На машинах, для которых был изобретен C, операции с 16-битными значениями стоят столько же, сколько операции с 8-битными значениями.Повышение значений char до int и усечение результатов при сохранении обратно в char было на самом деле дешевле и проще, чем непосредственное выполнение арифметики со значениями char.В то время как стандарт C, после его публикации, предписывает, что все реализации C должны преобразовывать все целочисленные значения в тип int, который может соответствовать как минимум диапазону -32767..32767 или типу unsignedкоторый может вместить не менее 0,65535 или более крупного типа, компиляторы 1980-х годов, нацеленные на 8-битные машины, не всегда делают это.

Хотя в настоящее время может показаться сумасшедшим пытаться использовать компилятор Cне отвечающие этим требованиям, программисты в 1980-х годах часто сталкивались с выбором между использованием компилятора "C-ish" или написанием всего на ассемблере.Некоторые из правил в MISRA, включая правила «встроенного типа», были разработаны для обеспечения того, чтобы программы работали, даже если они выполняются в странных реализациях, которые обрабатывают int как 8-битный тип.

...