前言
之前分享了一些編程規(guī)范相關(guān)的文章,有位讀者提到了汽車電子行業(yè)的MISRA C標(biāo)準(zhǔn),說這個很不錯。
本次給大家找來了一篇汽車電子行業(yè)的MISRA C標(biāo)準(zhǔn)的文章一同學(xué)習(xí)下。
什么是MISRA?
MISRA(The Motor Industry Software Reliability Association),中文名稱為汽車工業(yè)軟件可靠性聯(lián)會,是英國的一個跨國汽車工業(yè)協(xié)會,其成員包括了大部分歐美汽車生產(chǎn)商。
其核心使命是為汽車工業(yè)提供服務(wù)和協(xié)助,幫助廠方開發(fā)安全的、高可靠性的嵌入式軟件。MISRA C則是由MISRA提出的針對嵌入式C語言開發(fā)標(biāo)準(zhǔn),目的是提高嵌入式系統(tǒng)的安全性、可讀性和可移植性。
MISRA C一開始主要是針對汽車產(chǎn)業(yè),后面他產(chǎn)業(yè)也逐漸開始使用MISRA C,包括航天、電信、國防、醫(yī)療設(shè)備、鐵路等領(lǐng)域中都已有廠商使用MISRA C。通常認(rèn)為,如果能夠完全遵守這些標(biāo)準(zhǔn),則該嵌入式C代碼就是易讀、可靠、可移植和易于維護(hù)的。
因此,很多嵌入式開發(fā)者都以MISRA C來衡量自己的編碼風(fēng)格,比如著名的uC/OS就稱自己99%的代碼遵循MISRA C編碼規(guī)范標(biāo)準(zhǔn)。
因此,作為嵌入式開發(fā)者,不論哪個行業(yè),都應(yīng)以產(chǎn)品安全性為前提,保證可靠性、可讀性、可移植性,也就是保證自身代碼盡可能符合MISRA C。
MISRA C應(yīng)用在越來越多領(lǐng)域,作為嵌入式開發(fā)者,編碼過程規(guī)范應(yīng)該盡可能遵循MISRA C規(guī)則,但也分特殊情況,有的時候為了嚴(yán)格按規(guī)范做可能會嚴(yán)重提高工作量或者降低系統(tǒng)性能,此時需要衡量一個平衡點。
關(guān)于MISRA C,本人的幾點體會。
1)編碼過程盡可能遵循MISRA C規(guī)范,提高代碼可靠性、可讀性、可移植。可靠性(穩(wěn)定性)是前提,可讀性、可移植是衡量一個程序員編碼水平的因素之一。
特別是對于嵌入式程序員,與硬件相關(guān)的編程,考慮到成本、供應(yīng)鏈等問題,硬件可能會經(jīng)常變動或者需要兼容多種硬件,此時,可移植性就體現(xiàn)出優(yōu)勢了,大大減少重復(fù)的編碼工作。
2)特殊情況下,是可以打破規(guī)則的。比如,其中禁止使用goto語句,也是相關(guān)標(biāo)準(zhǔn)要求禁止的。有些時候是可以使用的,而且使用其他會使得程序邏輯更清晰。但,如果“特殊情況”出現(xiàn)非常頻繁,那就得考慮自身的程序架構(gòu)是否合理了。
3)可以借助一些工具進(jìn)行MISRA C檢查。如IAR中,就有支持MISRA C規(guī)則檢查。以下為MISRA C 2004規(guī)范標(biāo)準(zhǔn)。
環(huán)境
規(guī)則1.1(強(qiáng)制):所有的代碼應(yīng)該遵守 ISO 9899:1990“Programming Language C”
規(guī)則1.2(強(qiáng)制):只有當(dāng)具備統(tǒng)一接口的目標(biāo)代碼的時候才可以采用多種編譯器和語言。
規(guī)則1.4(強(qiáng)制):檢查編譯器 / 連接器以確保支持 31 一個有效字符,支持大小寫敏感。
語言擴(kuò)展
Rule 2.1(強(qiáng)制):匯編語言應(yīng)該封裝起來并且隔離。
例如:#define NOP asm( “NOP”)
規(guī)則2.2(強(qiáng)制):源代碼只能采用 /* … * /風(fēng)格的注釋。
規(guī)則2.3(強(qiáng)制):字符序列 /* 不能在注釋中使用。
注: C 語言不支持注釋的嵌套即使一些編譯器支持這個語言擴(kuò)展。
規(guī)則2.4(建議):代碼段不能注釋掉。
注:應(yīng)采用 #if 或者#ifdef 來構(gòu)成一個注釋,否則代碼里如果有注釋會改變代碼的作用。
文檔化
規(guī)則3.3(建議):編譯器對于整數(shù)除法運算的實施應(yīng)該寫入文檔。
例:
-5/3=-1余-2有些編譯器結(jié)果是-2于+1。
字符集
規(guī)則4.1(強(qiáng)制):只能使用 ISO 標(biāo)準(zhǔn)定義的字符集。
標(biāo)識符
規(guī)則6.5 (強(qiáng)制):在內(nèi)部范圍的標(biāo)識符不能和外部的標(biāo)識符用同樣的名字,因為會隱藏那個標(biāo)識符。例:
int16_ti: voidf() { int16_ti; i=3; }
規(guī)則5.2(強(qiáng)制):typedef 名稱只能唯一,不能重復(fù)定義。
規(guī)則5.4(強(qiáng)制):標(biāo)記名應(yīng)該是唯一的標(biāo)識符。
規(guī)則5.7(建議):標(biāo)識符不能重復(fù)使用。
類型
規(guī)則6.1(強(qiáng)制):char 類型只能用來存儲使用字符。
規(guī)則6.2(強(qiáng)制):signed 和 unsigned char 只能用來存儲和使用數(shù)據(jù)值.
規(guī)則6.3(建議):對于基本數(shù)據(jù)類型,必須使用typedef顯式標(biāo)識出數(shù)據(jù)長度。
例:
typedefsignedcharint8_t; typedefunsignedintuint16_t;
約束
規(guī)則7.1(強(qiáng)制):禁止使用八進(jìn)制數(shù)(0除外)或者八進(jìn)制轉(zhuǎn)義字符。
注:整型常數(shù)以 0開始會被認(rèn)為是八進(jìn)制。例:
code[1]=109 code[2]=100 code[3]=052
如果是對總線消息初始化,會有危險。
聲明和定義
規(guī)則8.1(強(qiáng)制):函數(shù)都應(yīng)該有原型聲明,且相對函數(shù)定義和調(diào)用可見。
規(guī)則8.2(強(qiáng)制):無論何時一個對象和函數(shù)聲明或者定義,它的類型應(yīng)該明確聲明 。
規(guī)則8.3(強(qiáng)制):函數(shù)聲明中的參數(shù)類型應(yīng)該和定義中的類型一致。
規(guī)則8.4(強(qiáng)制):如果對象或函數(shù)被聲明了多次,那么它們的類型應(yīng)該是兼容的。
規(guī)則8.5(強(qiáng)制):頭文件中不應(yīng)定義對象或者函數(shù)。
規(guī)則8.6(強(qiáng)制):函數(shù)應(yīng)該聲明為具有文件作用域。
規(guī)則8.7(強(qiáng)制):如果對象的訪問只是在單一的函數(shù)中,那么對象應(yīng)該在塊范圍內(nèi)聲明。
規(guī)則8.8(強(qiáng)制):外部變量或者函數(shù)只能聲明在一個文件中。
規(guī)則8.9(強(qiáng)制):具有外部鏈接的標(biāo)識符應(yīng)該具有準(zhǔn)確的外部定義。
規(guī)則8.10(強(qiáng)制):在文件范圍內(nèi)聲明和定義的所有對象或函數(shù)具有內(nèi)部鏈接,除非是在需要外部鏈接的情況下。
規(guī)則8.11(強(qiáng)制):static存儲類標(biāo)識符應(yīng)該用于具有內(nèi)部鏈接對象和函數(shù)的定義和聲明。
規(guī)則8.12(強(qiáng)制):數(shù)組聲明為外部,應(yīng)該明確聲明大小或者直接初始化確定。
初始化
規(guī)則9.1(強(qiáng)制):所有變量在使用之前都應(yīng)該賦值。
規(guī)則9.2(強(qiáng)制):應(yīng)該使用大括號一指示和匹配數(shù)組和結(jié)構(gòu)的非零初始化構(gòu)造。
規(guī)則9.3(強(qiáng)制):在枚舉列表中,”=“不能顯式用于除首元素之外的元素上,除非所有的元素都是顯式初始化的。
數(shù)學(xué)類型轉(zhuǎn)換(隱式)
規(guī)則10.1(強(qiáng)制):整型表達(dá)式不要隱式轉(zhuǎn)換為其他類型。
1)轉(zhuǎn)換到更大的整型。
2)表達(dá)式太復(fù)雜。
3)表達(dá)式不是常數(shù)是一個函數(shù)。
4)表達(dá)式不是一個常數(shù)是一個返回表達(dá)式。
規(guī)則10.2(強(qiáng)制):浮點數(shù)表達(dá)式不要隱式轉(zhuǎn)換為其他類型。
1)轉(zhuǎn)換到更大的浮點數(shù)。
2)表達(dá)式太復(fù)雜。
3)表達(dá)式是一個函數(shù)。
4)表達(dá)式是一個返回表達(dá)式。
數(shù)學(xué)類型轉(zhuǎn)換(明確)
規(guī)則10.3(強(qiáng)制):整型表達(dá)式的值只能轉(zhuǎn)換到更窄小且是同樣符號類型的表達(dá)式。
規(guī)則10.4(強(qiáng)制):浮點表達(dá)式的值只能轉(zhuǎn)換到更窄小的浮點表達(dá)式。
規(guī)則10.5(強(qiáng)制):如果位運算~和<<應(yīng)用在基本類型為unsigned char 或unsigned short的操作數(shù),結(jié)果應(yīng)該立即強(qiáng)制轉(zhuǎn)換為預(yù)期操作數(shù)的基本類型。例:
uint8_ta=0x5a; uint8_tb; b=((uint8_t)(~a))>>4;
數(shù)學(xué)類型轉(zhuǎn)換
規(guī)則10.6(強(qiáng)制):所有的 unsigned 類型都應(yīng)該有后綴“U”。
規(guī)則11.1(強(qiáng)制):指針不能轉(zhuǎn)換為函數(shù)或者整型以外的其他類型。
表達(dá)式
規(guī)則12.2(強(qiáng)制):表達(dá)式的值應(yīng)和標(biāo)準(zhǔn)允許的評估順序一致。例:
x=b[i]+i++;
不同的編譯器給出的結(jié)果不一樣,b[i] 是否先執(zhí)行?應(yīng):x=b[i]; i++; 比如:
x=func(i++,i);
規(guī)則12.3(強(qiáng)制):sizeof 操作符不能用在包含邊界作用(side effect) 的表達(dá)式上。例:
int32_t=i; int32_t=j; j=sizeof(i=1234);
表達(dá)式并沒有執(zhí)行,只是得到表達(dá)式類型int的size。
規(guī)則12.4(強(qiáng)制):邏輯操作符 && 或者||右邊不能包含邊界作用 (side effect)。
例:
if(ishight)&&(x==i++))
如果 ishight =0 那么 i++不會評估
規(guī)則12.5(建議):++和- - 不能和其他表達(dá)式用在一個表達(dá)式中。
例:
u8a=++u8b+u8c–;
控制語句表達(dá)式
規(guī)則13.1(強(qiáng)制):賦值語句不能用在一個產(chǎn)生布爾值的表達(dá)式中。
例:
if((x=y)!=0)… if(x=y)…
規(guī)則13.3(強(qiáng)制):浮點表達(dá)式不應(yīng)該測試其是否相等或者不相等。
規(guī)則13.4(強(qiáng)制):for控制表達(dá)式中不要包含任何浮點類型。
規(guī)則13.6(強(qiáng)制):數(shù)字變量作為for循環(huán)的循環(huán)計數(shù)不要在循環(huán)體內(nèi)部被修改。
例:
flag=1; for(i=0;(i<5)&&(flag==1);i++)? {? ????flag=0;? ????i=i+3;? }?
控制流
規(guī)則14.1(強(qiáng)制):不要有執(zhí)行不到的代碼。
例:
swich(event) { case0; do_wakeup(); break; do_more(); … }
規(guī)則14.4(強(qiáng)制) :goto 語句不能使用。
規(guī)則14.5(強(qiáng)制):continue 不能使用。
規(guī)則14.6(強(qiáng)制):函數(shù)應(yīng)在函數(shù)結(jié)束有一個出口。
規(guī)則14.7(強(qiáng)制):witch、while do 、while for 語句體應(yīng)是一個混合語句。
規(guī)則14.10(強(qiáng)制):所有if else if 結(jié)構(gòu)都應(yīng)該由 else 結(jié)束。
switch(x) { uint8_tvar;/*違反*/ case0: … }
函數(shù)
規(guī)則16.2(強(qiáng)制):函數(shù)不能直接或者間接的調(diào)用自己。
例:系統(tǒng)不能用遞歸,超出堆??臻g很危險。
規(guī)則16.8(強(qiáng)制):non-void 類型函數(shù)的所有出口路徑都應(yīng)該有一個明確的return 語句表達(dá)式。
指針和數(shù)組
規(guī)則17.1(強(qiáng)制):指針的數(shù)學(xué)運算只能用在指向數(shù)組的地址上。
規(guī)則17.3(強(qiáng)制):>,>=,<,<= 不能用在指針類型,除非指向同一個數(shù)組。
規(guī)則17.5(建議):禁止使用 2 級以上指針。
結(jié)構(gòu)和聯(lián)合
規(guī)則18.4(強(qiáng)制):禁止使用union(共用體)。
預(yù)處理指令
規(guī)則19.1(建議):#include 語句的前面只能有其他預(yù)處理指令和注釋。
規(guī)則19.2(建議):#include 指令中的頭文件名稱不能包含非標(biāo)準(zhǔn)的字符。
規(guī)則19.5(強(qiáng)制):宏不能在函數(shù)體內(nèi)定義。
規(guī)則19.8(強(qiáng)制):類函數(shù)宏調(diào)用時不能沒有它的參數(shù)。
標(biāo)準(zhǔn)庫
規(guī)則20.1(強(qiáng)制):標(biāo)準(zhǔn)庫中的保留標(biāo)識符,宏和函數(shù)不能定義,重定義和undefined。
規(guī)則20.4(強(qiáng)制):動態(tài)內(nèi)存分配不能使用。
例:不能使用malloc、calloc、free、realloc。
規(guī)則20.9(強(qiáng)制):輸入輸出庫 (stdio.h) 不能用在產(chǎn)生嵌入式系統(tǒng)中。
規(guī)則20.12(強(qiáng)制):時間處理函數(shù) time.h不能使用。
運行時故障
規(guī)則21.1(強(qiáng)制):通過使用以下手段確保把運行時故障最小化。
1)靜態(tài)分析工具/技術(shù)。
2)動態(tài)分析工具/技術(shù)。
3)編寫明確的代碼避免運行時錯誤。
-
嵌入式
+關(guān)注
關(guān)注
5082文章
19104瀏覽量
304793 -
汽車電子
+關(guān)注
關(guān)注
3026文章
7941瀏覽量
166899 -
代碼
+關(guān)注
關(guān)注
30文章
4779瀏覽量
68521 -
MISRA
+關(guān)注
關(guān)注
0文章
21瀏覽量
6963
原文標(biāo)題:汽車電子行業(yè)的 C 語言編程標(biāo)準(zhǔn)
文章出處:【微信號:嵌入式開發(fā)愛好者,微信公眾號:嵌入式開發(fā)愛好者】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論