2015-05-14 35 views
10

在調試一些嵌入式代碼,我遇到事情就這樣的:MISRA遞增用C

buffPtr = &a[5]; 
buffEndPtr = &a[10]; 

while (buffPtr != buffEndPtr) 
{ 
    *buffPtr = 0xFF; 
    buffPtr = &buffPtr[1];   /* MISRA improvement for: buffPtr++ */ 
} 

爲什麼會變成這樣構造結束(* buffPtr)的改善++?

+0

因爲'(* buffPtr)++'會出錯。你的意思是'* buffPtr ++ = 0xFF;'? – mch

+2

@mch我想這是問題主體中的錯字。請參閱代碼中的評論。 –

回答

10

有一個MISRA規則,指出允許的唯一指針數學是索引操作。

您顯示的模式是執行不力的解決方法。這是醜陋/奇怪/不常見的,可能是基於對該規則目的的誤解。它也可能違反另一條規則。

一種更好的方式來寫這個代碼將是:

for(i=5; i < 10; i++) 
{ 
    a[i] = 0xff; 
} 

更新2015年5月20日 - 由於這是在這裏接受的答案是實際的規則違反,embedded.kyle的禮貌:

MISRA-C:2004,規則17.4(必需)或MISRA-C:2012,規則18.4(必需) 數組索引應是唯一允許的指針運算形式。

+0

原始代碼絕對是規則的「解決方案」,而不是因爲它們的「改進」。 for循環是正確的模式。 – AShelly

+0

是的,想一想,我猜'memset'本身甚至不符合MISRA標準。所以即使在它能夠工作的情況下,這也不符合MISRA的要求。 –

9

(*buffPtr)++違反規則是:

MISRA-C:2004年,第17.4(必需)或MISRA-C:2012年,第18.4(必需)

數組索引應是唯一允許的指針算術形式。

他們這一規則背後的推理:使用數組下標語法,ptr[expr]

數組索引,是指針運算的 優選形式,因爲它通常是清晰和比指針操作容易 因此更小的誤差。任何明確的 計算出的指針值都有可能訪問意外或無效的內存地址。這種行爲也可以通過數組 編制索引,但下標語法可能會減輕人工審查的工作量。用C

指針運算可以是混亂的新手錶達 ptr+1可能被錯誤地解釋爲在加入1ptr保持的 地址。實際上,新的內存地址取決於指針目標的大小(以字節爲單位)。如果sizeof應用不正確,這種誤解會導致 意外行爲。

MISRA的許多規則都有類似的理由。基本上他們的思考過程是,如果你儘可能簡單明確地編寫代碼,代碼將更具可讀性和可維護性,因此會導致本質上更安全的代碼。更安全的代碼是MISRA標準背後的目的。

正如Brian指出的那樣,有些方法可以編寫符合MISRA規範的代碼,但仍違反規則背後的意圖。在我看來,Brian的for循環例子將是最常見和容易理解的結構。

+1

糾錯:MISRA-C:2012允許++,但不允許+。它與MISRA-C:2004中引用的規則不同,也更爲寬鬆。 – Lundin

5

在MISRA-C:2004規則17.4中,有禁止所有形式的指針算術的諮詢規則。這樣做的目的是好的,該規則的目的是爲了禁止潛在危險的代碼,如嘗試:

stuff* p; 
p = p + 5; // 5 stuff, not 5 bytes, bug or intentional? 

和難以閱讀的代碼,如

*(p + 5) = something; // harder to read but equivalent to p[5] 

一般而言,其目的是在循環指向數據時,建議使用整數迭代器而不是指針算術。

但是,該規則還禁止了各種可能不危險的基本指針操作,例如ptr++。一般來說,這個規則太嚴格了。

在MISRA-C:2012中,這條規則(18.4)放寬,只禁止+ - += -=運營商。


在你的情況下,buffPtr = &buffPtr[1];是引入歧途的企圖閃避規則17.4,因爲該規則並沒有多大意義。相反,程序員決定混淆他們的程序,使其不易讀,因此不太安全。

解決這個問題的正確方法是使用++運算符並忽略規則17.4。這是一個顧問規則,因此不需要做任何偏差(除非由於某種原因本地MISRA-C實現另有說明)。如果您確實需要偏離,您可以簡單地說,該規則對++運算符沒有任何意義,然後參考MISRA-C:2012 18.4。

(當然,整個循環改寫到一個for循環,如圖另一個答案是最好的解決辦法)

編程,而無需使用常識總是很危險的,因爲是盲從MISRA不理解的聲音理由背後的規則,或在這種情況下缺乏這樣的。

+0

我判斷規則的意圖是要求所有指針對象標識分配的開始,這是其他語言(如標準Pascal)中的語義限制。具有這種語義限制的C方言將無法完成在C中可以完成的所有事情,但是這種方言的實現可以支持以「全功率」C中不可能的方式進行數組邊界檢查。支持編譯器支持的數組邊界檢查在某些需要故障安全的系統中可能會有所幫助。 – supercat