Нарушение MISRA 2012 - несоответствие типов (правила 10.1, 10.4) - PullRequest
0 голосов
/ 07 июня 2018

Мне грозит нарушение MISRA C 2012, которое я не могу понять.Ниже приведен код:

#define I2C_CCRH_FS      ((uint8_t)0x80)
#define I2C_CCRH_DUTY    ((uint8_t)0x40)
#define I2C_CCRH_CCR     ((uint8_t)0x0F)

typedef struct I2C_struct
{
  volatile uint8_t CR1;
  volatile uint8_t CR2;
  volatile uint8_t CCRL;
  volatile uint8_t CCRH;
} I2C_TypeDef;

#define I2C_BaseAddress         0x5210
#define I2C ((I2C_TypeDef *) I2C_BaseAddress)

I2C->CCRH &= ~(uint8_t)((I2C_CCRH_FS | I2C_CCRH_DUTY) | I2C_CCRH_CCR);

В предыдущем коде PC-Lint жалуется, что:

Unpermitted operand to operator '|' [MISRA 2012 Rule 10.1, required]

Mismatched essential type categories for binary operand [MISRA 2012 Rule 10.4, required]

Правило 10.1 гласит, что не должно быть проблем ИЛИ unsigned int s.( PC-Lint проходит первую операцию ИЛИ и жалуется на вторую !! )

Правило 10.4 гласит, что операнды операции должны иметь один и тот же существенный тип.

Я не могу понять, почему существуют эти нарушения, хотя все операнды объявлены как uint8_t?

Я пытался поместить скобки вокруг каждой из двух констант ORed.Я также попытался привести их всех к uint8_t и volatile uint8_t.Не устранено нарушение.

Я проверил эти два сообщения ( 1 , 2 ), но они не отвечают на мой вопрос.

Ответы [ 2 ]

0 голосов
/ 08 июня 2018

I2C_CCRH_FS | I2C_CCRH_DUTY сама по себе совместима с MISRA.Оба операнда по существу без знака, так что подвыражение в порядке.Однако все еще существует неявное преобразование каждого операнда в int.Практический результат имеет тип int.

. В псевдокоде: когда вы делаете (result as int) | I2C_CCRH_CCR, операнды перед неявным продвижением имеют типы int | uint8_t.uint8_t получит здесь целое число до int.У вас есть операнды разной подписи.

(Я полагаю, что инструмент жалуется на 10,4, поскольку целочисленные продвижения являются частью обычного арифметического разговора, как и в 10,4.)

Это целоеВыражение не вызывает никаких проблем на практике, поэтому предупреждение в основном педантичное.Но представьте, если бы вы сделали ~(I2C_CCRH_FS | I2C_CCRH_DUTY) | I2C_CCRH_CCR) без приведения - вы бы получили отрицательное число, что-то вроде 0xFFFFFFxx, выраженное в дополнении к 2.Это может быть опасно.

Чтобы исправить это, у вас есть два варианта:

  • Для каждой операции приведите результат обратно к предполагаемому типу.Часто это дух MISRA-C.
  • Перед операцией приводите операнды к большому типу без знака.Обычно более читаемый IMO.

Обратите также внимание, что оператор ~ не должен использоваться со операндом со знаком!Это нарушение правила 10.1.Приведение обратно к uint8_t должно быть сделано последним.


TL; DR.Как получить код, совместимый с MISRA:

Вы должны были бы сделать что-то наполовину ужасное, как это:

I2C->CCRH &= (uint8_t) ~ (uint8_t) ((uint8_t)(I2C_CCRH_FS | I2C_CCRH_DUTY) | I2C_CCRH_CCR)

Это немного беспорядок.Я бы вместо этого бросил заранее.Предполагается, что 32-битный процессор:

I2C->CCRH &= (uint8_t) ~( (uint32_t)I2C_CCRH_FS    |  // comment explaining FS
                          (uint32_t)I2C_CCRH_DUTY) |  // comment explaining DUTY
                          (uint32_t)I2C_CCRH_CCR   ); // comment explaining CCR

Вышеуказанный стиль полезен при работе с регистрами MCU и аналогичными.Этот код является приемлемым, но его можно еще упростить.

Если можно изменить определения на #define I2C_CCRH_FS 0x80u, тогда вы получите:

I2C->CCRH &= (uint8_t) ~(I2C_CCRH_FS | I2C_CCRH_DUTY | I2C_CCRH_CCR);

, и он все равно будет совместим с MISRAиз-за удобного маленького суффикса u, который нравится MISRA.

0 голосов
/ 07 июня 2018

При выполнении побитовой операции (I2C_CCRH_FS | I2C_CCRH_DUTY) результат переводится в целое число.См. Правила целочисленного продвижения Здесь

Следовательно, возникает несовпадение между результатом вышеуказанной операции и следующим побитовым ИЛИ | I2C_CCRH_CCR

Чтобы исправить это, необходимо добавитьприведение к результату ОБА битовых операций ИЛИ.

Первое приведение требуется для приведения результата оператора ~ из int обратно в unsigned

I2C->CCRH &= (uint8_t)~(uint8_t)((uint8_t)(I2C_CCRH_FS | I2C_CCRH_DUTY) | I2C_CCRH_CCR);

Объяснить

I2C->CCRH &= (uint8_t)~    // Required to cast result of ~ operator to uint8_t
             (uint8_t)     // Casts the result of the 2nd OR to uint8_t
             ((uint8_t)    // Casts the result of the 1st OR    
              (I2C_CCRH_FS | I2C_CCRH_DUTY)  // 1st OR
              | I2C_CCRH_CCR);      // 2nd OR
...