1. 程式人生 > 其它 >extern 定義_功能安全實踐 | 定義程式設計Style和命名規則

extern 定義_功能安全實踐 | 定義程式設計Style和命名規則

技術標籤:extern 定義標頭檔案定義全域性變數巨集定義中有浮點數高質量c++程式設計指南

點選上方?“汽車知識共享空間”關注訂閱號,設為星標⭐獲取更多實時內容更新。。。

功能安全標準ISO26262-6 Table1的1g中推薦ASIL B及高於ASIL B等級的程式碼需要use of style guides(使用風格指南)所有涉及功能安全的程式碼都需要使用命名規則(1.h Use of naming conventions).什麼是風格指南?為什麼會有這樣的要求,筆者初次接觸這個要求時也十分茫然,我寫的程式碼只要過了單元測試不就可以了麼?為什麼一定要定義風格呢?

首先咱們一起來看看為什麼這個問題。

剛學程式設計的時候,老師通常會說養成良好的程式設計習慣,比如,變數的名字要有意義不要單純的用x,y,a,b,c這樣的字母來對形參命名。筆者工作至今,老師當年有一個問題今天回憶起來依然記憶猶新。你今天寫了一段程式碼,過三個月後你回來再看這段程式碼,你需要花多長時間能讀懂它?如果看程式碼的人不是你,又需要花多長時間可以看懂這段程式碼?

所謂程式設計風格(Programming Style)可以理解為程式設計師在寫程式碼的時候需要使用的一系列規則或者或者指南,這些規則或者指南的目的是幫助自己或者他人來準確、快速的理解程式碼需要表達的內容。好的程式設計風格指南可以增加程式的可讀性,消除對程式碼理解上的歧異

,無論是是對單元測試還是程式碼評審驗證甚至後期的維護升級都可以帶來便利。

另一方面,我們參考文章《汽車電子讀書筆記-專業術語解析03-失誤、偏差與失效》從fault、error、failure三者之間的關係出發,好的程式設計風格可以從源頭上降低fallt發生的可能性。

正是因為有上面介紹的這些優點,可以明顯改善安全相關軟體的程式碼質量。所以,26262才推薦我們來使用程式設計風格指南。同理,命名規則的好處也是如此。雖然,功能安全標準推薦ASILB及以上等級系統使用程式設計風格指南,但是,從開發以及使用的角度出發,尤其是比較複雜的程式,無論你是否涉及安全,筆者建議都應該使用程式設計風格指南(Programming Style Guideline)。

說了這麼多好處,接下來讓我們來一起看看如何定義好的程式設計風格指南

筆者是從事C語言開發相關工作的,就以C語言為例進行說明,此處需要說明一點。由於不同的程式語言在語法規則上會有些許的不同,所以很多規則不一定具有廣泛的適用性。需要各位讀者結合自己的應用情況進行調整

1.檔案的組織與引用

對於複雜系統,尤其是那些以萬行為單位來計算的軟體,不可能只有一個模組,也不可能只有一個.c檔案。如果你的系統需要分成若干個.c檔案的話,必然會涉及檔案的引用問題。我們都知道C語言屬於編譯型語言,C語言的原始程式碼在編譯轉化的過程中是以.C為基礎進行的即以單個.C檔案為單位進行編譯。C語言的程式碼在編譯之前需要進行預處理來整合標頭檔案也就是平時我們看到的.h。筆者這裡推薦的好的程式設計風格就與預處理相關。

1.1所有與本模組相關的自定義型別typedef都放在一個頭檔案中。比如模組A的原始檔是Module_A.c那麼,所有與Module_A模組相關的typedef都放在Module_A.h這個檔案中。為什麼要這麼做,主要是,如果所有與本模組相關的typedef有的出現在原始檔.c中,有的出現在.h標頭檔案中的話,會降低程式的可讀性增加更改的難度。而且,如果,涉及到跨模組的引用怎麼辦?總不大可能直接引用.c吧。

1.2所有的巨集定義必須放在標頭檔案中完成,此處最好規定好命名規則比如,所有涉及巨集的內容的標頭檔案因為常常與配置相關,可以規定它的名字中包含cfg(configration的縮寫)來與其他的標頭檔案進行區分。

1.3所有的全域性變數都必須加static字首,當然也可以在程式設計風格中規定,所有extern的全域性變數只能在.c中定義一次,並且只能在.h檔案中進行宣告。但是,按照功能安全的標準我們真的不希望出現extern的變數(extern 的const型別沒有問題哈,這個是常量不涉及意外更改),具體怎麼處理可以參考文章《功能安全實踐 | 如何安全使用全域性變數》。

1.4 所有的static函式都必須在原始檔的頭部宣告函式原型。為什麼會有這條規定,是因為萬一函式在原始檔中的順序調整了,你要保證存在呼叫關係的函式不會報錯。

1.5所有的全域性函式都只能在標頭檔案中定義函式原型即用extern進行宣告,不允許在.c中進行extern宣告。為什麼要做這條規定,是因為呼叫的時候最佳的方式是調標頭檔案。

1.6 每行只允許存在一個變數定義或者宣告

2 縮排的使用:

我們先來看一段沒有縮排定義的程式碼;

#include <stdio.h>

int main(void) {

int seg[10] = {6,2,5,5,4,5,6,3,7,6};

int d1, d2, d3, d4, m=0, td, ts;

for (d1=0; d1<2; d1++)

for (d2=0; d2<10; d2++)

for (d3=0; d3<6; d3++)

for (d4=0; d4<10; d4++)

if ((!((d1==0)&&(d2==0))) && (!((d1==1)&&(d2>2)))) {

if (d1==0) {

ts = seg[d2] + seg[d3] + seg[d4];

td = d2 + d3 + d4;

if (ts == td) { m++;

printf(" %1d:%1d%1d\n",d2,d3,d4); }

} else {

ts = seg[d1] + seg[d2] + seg[d3] + seg[d4];

td = d1 + d2 + d3 + d4;

if (ts == td) { m++;

printf("%1d%1d:%1d%1d\n",d1,d2,d3,d4); }

} }

return 0; }

無論你是否學過C語言看到這段程式碼,大部分人的第一印象都會是,這是什麼東西3c44bdca55abcc04abae0f96448c5746.png

讓我們增加一下縮排,再來看一下:

#include<stdio.h>

intmain(void)

{

intseg[10] = {6,2,5,5,4,5,6,3,7,6};

intd1, d2, d3, d4, m=0, td, ts;

for(d1=0; d1<2; d1++)

for(d2=0; d2<10; d2++)

for(d3=0; d3<6; d3++)

for(d4=0; d4<10; d4++)

if(

( !(

(d1==0) && (d2==0)

)

)

&&

( !(

(d1==1) && (d2>2)

)

)

)

{

if(d1==0)

{

ts = seg[d2] + seg[d3] + seg[d4];

td = d2 + d3 + d4;

if(ts == td)

{

m++;

printf(" %1d:%1d%1d\n",d2,d3,d4);

}

}

else

{

ts = seg[d1] + seg[d2] + seg[d3] + seg[d4];

td = d1 + d2 + d3 + d4;

if(ts == td)

{

m++;

printf("%1d%1d:%1d%1d\n",d1,d2,d3,d4);

}

}

}

return0;

}

同樣的一段程式碼,層次分開後的可讀性明顯改善。

2.1每個指令塊至少縮排2個空格(有些推薦4個空格)。這樣的話你的程式碼層次會非常清楚。

2.2涉及到多層運算的語句需要展開,並且保證相同層次的括號對齊。為什麼要增加這條約束,主要是因為,比如例子中的第一個if,如果你是基於程式碼的開發,不小心漏掉一個括號。如果編譯階段報錯的話,沒有清晰的層次,你很難知道自己的編碼在什麼地方出了錯。

2.3程式碼塊中大括號"{"或者“}”需要單獨保持一行,並且對齊。這項要求的原因與2.2一樣。

3.空格與空行

因為示例程式碼太佔空間了,咱們接下來就直接寫結論了。

3.1變數與函式之間的定義需要留空白行

3.2 函式與函式之間需要留空白行。

3.3二目運算子兩邊需要留空格

縮排案例中使用的示例程式碼,是明顯不符合MISRA C2012要求的,無論是變數的定義還是註釋(程式碼根本就沒有註釋289e2ae67a397d8ba7f6bf3749680b43.png,要求更加嚴格的程式碼,會要求HIS指標中註釋密度,這個留在後續文章中給大家講)。對於註釋,本文在註釋方面的解釋還不夠完善,比如可以根據您所在公司的現狀,定義標準的註釋標頭檔案,同時還需要結合程式碼寫作習慣規定好註釋的具體位置(比如,註釋只允許出現被註釋程式碼的上方或者右側等)。MISRAC中也有很多細節的要求比如不可以用//。另外,對於巨集也是,比如,MISRA C 2012不建議用#if define,標頭檔案必須用巨集來限制編譯範圍等。這些屬於MISRA C中有明確要求的本文就不再贅述。如果讀者感興趣,可以留言,筆者後續可以再整理一下關於MISRA C中提到的C語言約束。

4命名規則。

我們接下來看看命名規則,常用的命名規則主要有以下兩種:

a.駱駝規則(camel naming rule)這種命名方法一般是第一個單詞的首字母小寫,後續單詞的每一個首字母大寫。就像駱駝的駝峰一樣。一般變數名稱,需要使用駱駝規則進行命名。

b. Pascal命名規則(Pascal naming rule),這種命名規則是所有單詞的首字母都使用大寫,一般用來給函式命名。

重點來了,其實你可以兩種規則都不用,也可以只選擇一種使用。如果你用的是autosar,可以直接使用autosar命名規則。如果不是autosar,那麼筆者建議可以採用如下命名規則:

模組名稱_功能名稱_子功能名稱

其中模組名稱可以採用首字母縮寫的形式,比如Electronic stability control 可以直接縮寫成ESC,後面的功能名稱和子功能名稱,可以視你選擇的C語言版本已經目標晶片的位寬來進行具體的長度限制或者縮寫分類

上面這些意見,結合一定的虛擬碼說明與MISRA C2012的相關規定,就可以設計出符合功能安全標準,同時屬於您自己公司的C語言程式設計風格指南。當然還有更多好的風格建議期待您的補充,如果,您有更多的關於C語言程式設計風格的建議,非常歡迎您在文章下方留言,供大家一起分享討論。

d319db37d05005598d3e55d624607c23.png