2015-12-02 6 views
2

Я написал следующий кусок кода, который MISRA не любит:нарушение Мишра с оператором побитового

UartPtr->C &= ((uint8_t)(~SIO_C2_SBK)); 

с

#define SIO_C2_SBK ((uint8_t)0x01u) 

и UartPtr определяется как

UartPtr = (UartStruct*) 0x12345678; /* I know that this is also a violation of MISRA */ 

с базовая структура данных:

typedef volatile struct UartStructTag 
{ 
    uint8_t  BDH; 
    uint8_t  BDL; 
    uint8_t  C1; 
    uint8_t  C2; 
} UartStruct; 

Моего Мишр проверка жалуется на первую линии и состояниях, которые

Целое константы с отрицательным значением преобразовывается в беззнаковый тип.

Однако, следующая строка не дает в проблему с MISRA:

UartPtr->C |= ((uint8_t)(SIO_C2_SBK)); 

Таким образом, проблема исходит из побитового отрицания. Но поскольку все операции напрямую передаются в uint8_t, я не нарушаю стандарт MISRA. Кто хочет мне помочь?

+1

Ну, '~ SIO_C2_SBK' - отрицательное значение, поэтому сообщение действительно точным. –

+0

Какая версия MISRA? Какой инструмент вы используете? – Lundin

+0

@ Lundin: Я использую QAC 7 с MISRA 2004 – m47h

ответ

4

В любом арифметическом выражении значения типов, меньших, чем int, неявно преобразуются в int перед их обработкой. Язык C не может выполнять арифметику по типам, меньшим, чем int. Таким образом, ваш код на самом деле ведет себя так:

UartPtr->C &= ((uint8_t)(~(int)(uint8_t)0x01u)); 

который только

UartPtr->C &= ((uint8_t)(~1)); 

где ~1 имеет значение -2 на дополнение до двух архитектур.

Чтобы устранить эту проблему, конвертировать в unsigned или любого другого знака типа больше, чем int перед нанесением побитовое: не

UartPtr->C &= ((uint8_t)(~(unsigned)SIO_C2_SBK)); 
+0

Так вот почему это правило, если, например, SIO_C2_SBK будет отрицательной подписанной константой, операция в конечном итоге не даст желаемого результата, и приведение скрывает это? – m47h

+1

@ m47h Правило скорее пытается защитить вас от ситуаций типа 'if (~ SIO_C2_SBK> 0)', которые не будут вести себя так, как ожидалось. Это одна очень неприятная ошибка для отслеживания. – Lundin

3

~ оператор, как и большинство операторов C, будет делать неявное целое преобразование операнда до применения оператора.

#define SIO_C2_SBK ((uint8_t)0x01u) 

Так выше макрос является проблемой, потому что вы вынуждаете буквальные вниз от unsigned int типа в небольшой целочисленном тип, который будет получать неявно способствовал. Вместо uint8_t вы получаете int, перед применением ~.

Это нарушает правило 10.1 MISRA-C: 2004, которое не допускает неявных преобразований, которые дают тип различной подписываемости (такие преобразования опасны, поэтому это очень хорошее правило).

  • Если вам не нужен этот макрос, чтобы дать uint8_t, а затем просто уронить (uint8_t бросок, и что будет решить эту проблему.

  • Если этот макрос по какой-то причине необходимо дать uint8_t, а затем изменить код для этого (MISRA совместимый):

    UartPtr->C &= (uint8_t) ~(uint32_t)SIO_C2_SBK; 
    

    где uint32_t соответствует размеру int на данной платформе.

+0

Я не очень хорошо знаком с MISRA, но разве для маскировки с 'uint8_t' не требуется маскировка с' & 0xFF'? – user694733

+1

@ пользователь694733 Nope. Маскировка с '& 0xFF' по существу та же самая, что и приведение к' uint8_t'. Тем не менее, MISRA 10.5 явно требует, чтобы вы приводили результат оператора '~' к предполагаемому типу. – Lundin