MISRA-C :2004 規則常用要點

規則2.1 強制 彙編語言應該被封裝並隔離。
在需要使用匯編指令的地方建議以如下方式封裝並隔離這些指令
(a) 彙編函數(b) C 函數(c) 宏
出於效率的考慮有時必須要嵌入一些簡單的彙編指令如開關中斷
如果不管出於什麼原因需要這樣做那麼最好使用宏來完成
#define NOP asm (“ NOP”);
規則2.2 強制 源代碼應該使用 /*…*/ 類型的註釋 。
規則2.4 建議 代碼段不應被註釋掉(comment out)。
當源代碼段不需要被編譯時,應該使用條件編譯來完成(如帶有
註釋的#if或#ifdef結構)。爲這種目的使用註釋的開始和結束標記
是危險的,因爲C不支持嵌套的註釋,而且已經存在於代碼段中的任
何註釋將影響執行的結果 。
規則5.1 強制 標識符(內部的和外部的)的有效字符不能多於31。
規則6.1 強制 單純的char類型應該只用做存儲和使用字符值 。
規則6.2 強制 signed char和unsigned char類型應該只用做存儲
和使用數字值 。
有三種不同的char類型:單純的char,unsigned char,signed
char。unsigned char和signed char用於數字型數據;char用於字符
型數據。單純char類型的符號是實現定義的,不應依賴 。
單純char類型所能接受的操作只有賦值和等於操作符(=、
==、!= )。
規則6.3 建議 應該使用指示了大小和符號的typedef以代替基本
數據類型 。
不應使用基本數值類型char、int、short、long、float和doulbe。
而應使用特定長度(specific-length)的typedef規則。6.3幫助我
們認清存儲類型的大小,卻不能保證可移植性,這是因爲整數提升
(integral promotion的)不對稱性。關於整數提升的討論見節6.10
仍然很重要的是要理解整數大小的實現 。
程序員應該注意這些定義之下的typedef的實際實現 。
比如本文檔中建議爲所有基本數值類型和字符類型使用如下所示
的ISOPOSIX的typedef。對於32位計算機它們是:
typedef char char_t;
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
typedef signed long int64_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long uint64_t;
typedef float float32_t;
typedef double float64_t;
typedef long double float128_t;

在位域類型的說明中typedef是不必要的。
規則6.4 強制 位域只能被定義爲unsigned int或singed int類型。
規則6.5 強制 int類型的位域至少應該爲2 bits長度。
1 bit長度的有符號位域是無用的 。
規則7.1 強制 不應使用八進制常量(零除外)和八進制escape序
列 。
規則8.5 強制 頭文件中不應有對象或函數的定義。
頭文件應該用於聲明對象、函數、typedef和宏,而不應該包含或
生成佔據存儲空間的對象或函數(或它們的片斷的定義)。這樣就清
晰地劃分了只有C文件才包含可執行的源代碼,而頭文件只能包含聲
明 。
規則8.8 強制 外部對象或函數應該聲明在唯一的文件中。
規則8.10 強制 在文件範圍內聲明和定義的所有對象或函數應該具
有內部鏈接,除非是在需要外部鏈接的情況下。
如果一個變量只是被同一文件中的函數所使用,那麼就用static。
類似地,如果一個函數只是在同一文件中的其他地方調用,那麼就用
static。使用static存儲類標識符將確保標識符只是在聲明它的文件
中是可見的,並且避免了和其他文件或庫中的相同標識符發生混淆的
可能性 。
規則9.1 強制 所有自動變量在使用前都應被賦值 。

規則10.5 強制 如果位運算符 ~ 和 <<應用在基本類型爲
unsigned char或unsigned short的操作數,結果應
該立即強制轉換爲操作數的基本類型 。
當這些操作符~和<<用在small integer類型(unsigned char或
unsigned short)時,運算之前要先進行整數提升,結果可能包含並
非預期的高端數據位,例如:
uint8_t port = 0x5aU;
uint8_t result_8;
uint16_t result_16;
uint16_t mode;
result_8 = (~port) >> 4; /* not compliant */
~ port 的值在16 位機器上是0xffa5 , 而在32 位機器上是
0xffffffa5。在每種情況下,result的值是0xfa,然而期望值可能是
0x0a。這樣的危險可以通過如下所示的強制轉換來避免:
result_8 = ( ( uint8_t ) (~port ) ) >> 4; /* compliant */
result_16 = ( ( uint16_t ) (~(uint16_t) port ) ) >> 4 ; /* compliant */
當<<操作符用在small integer類型時會遇到類似的問題,高端數
據位被保留下來。例如:
result_16 = ( ( port << 4 ) & mode ) >> 6 ; /* not compliant */
result_16的值將依賴於int實現的大小。附加的強制轉換可以避
免任何模糊性 。
result_16 = ( ( uint16_t ) ( ( uint16_t ) port << 4 ) & mode ) >> 6 ; /* compliant
*/


規則10.6 強制 後綴“U”應該用在所有unsigned類型的常量上 。
規則12.7 強制 位運算符不能用於基本類型(underlying type)是
有符號的操作數上。
位運算(~、<<、>>、&、^ 和 |) 對有符號整數通常是無意義
的。比如:如果右移運算把符號位移動到數據位上或者左移運算把數
據位移動到符號位上,就會產生問題 。
規則12.9 強制 一元減運算符不能用在基本類型無符號的表達式
上。
規則12.10強制 不要使用逗號運算符。
規則13.5 強制 for語句的三個表達式應該只關注循環控制 。
for語句的三個表達式都給出時它們應該只用於如下目的 :
第一個表達式初始化循環計數器 (例子中的i );
第二個表達式應該包含對循環計數器(i)和其他可選的循環
控制變量的測試 ;
第三個表達式循環計數器(i)的遞增或遞減 。
規則14.5 強制 不應使用continue語句。
規則16.2 強制 函數不能調用自身不管是直接還是間接的。
規則16.7 建議 函數原型中的指針參數如果不是用於修改所指向的
對象就應該聲明爲指向const的指針。

本規則會產生更精確的函數接口定義const限定應當用在所指向
的對象而非指針因爲要保護的是對象本身。例如:
void myfunc ( int16_t *param1, const int16_t *param2, int16_t *param3 )
/* param1 : Addresses an object which is modified – no const
param2 : Addresses an object which is not modified – const required
param3 : Addresses an object which is not modified – const missing */
{
*param1 = *param2 + *param3;
return;
}
/* data at address param3 has not been changed, but this is not const therefore
not compliant */
規則19.10 強制 在定義函數宏時每個參數實例都應該以小括號括起
來除非它們做爲#或##的操作數。
函數宏的定義中參數應該用小括號括起來。例如一個abs函數可以
定義成 :
#define abs (x) ( ( (x) >= 0 ) ? (x) : -(x) )
不能定義成 :
#define abs (x) ( ( (x) >= 0 ) ? x : -x )
如果不堅持本規則,那麼當預處理器替代宏進入代碼時操作符優
先順序將不會給出要求的結果。
考慮前面第二個不正確的定義被替代時會發生什麼 。
z = abs ( a – b );
將給出如下結果:
z = ( ( a – b >= 0 ) ? a – b : -a – b );

子表達式 – a - b 相當於 (-a)-b而不是希望的 –(a-b)把所有
參數都括進小括號中就可以避免這樣的問題 。
規則19.15 強制 應該採取防範措施以避免一個頭文件的內容被包含
兩次。
規則20.3 強制 傳遞給庫函數的值必須檢查其有效性。
規則20.4 強制 不能使用動態堆的內存分配 。
這排除了對函數alloc、malloc、realloc和free的使用。
規則20.5 強制 不要使用錯誤指示errno 。
規則20.7 強制 不應使用setjmp宏和longjmp函數。
規則20.8 強制 不應使用信號處理工具<signal.h> 。
規則20.9 強制 在產品代碼中不應使用輸入/輸出庫<stdio.h>。
規則20.10強制 不應使用庫<stdlib.h>中的函數atof、atoi和atol。
當字符串不能被轉換時,這些函數具有未定義的行爲。
規則20.12強制 不應使用庫<time.h>中的時間處理函數。
規則21.1 強制 最大限度降低運行時錯誤必須要確保至少使用了下
列方法之一:
a) 靜態分析工具/技術;
b) 動態分析工具/技術 ;
c) 顯式的代碼檢測以處理運行時故障 。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章