2015-12-02 55 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