2015-12-02 59 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:我在MISRA 2004中使用QAC 7 – 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字面分解成小的整数类型,这将获得隐含提升。在应用~之前,您最终会以int而不是uint8_t

这违反规则MISRA-C的10.1: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

@ user694733没有。使用'&0xFF'掩盖本质上与转换为'uint8_t'相同。但是,MISRA 10.5明确要求您将'〜'运算符的结果转换为预期的类型。 – Lundin