作者 | 給你小魚干
小編 | 不吃豬頭肉
隨著汽車工業(yè)邁入數(shù)字化轉(zhuǎn)型的新紀元,軟件的安全性與可靠性已躍升為設(shè)計和開發(fā)核心環(huán)節(jié)的重中之重。MISRA C++標準的誕生與演進,精準地回應(yīng)了行業(yè)發(fā)展的需求。自MISRA C++標準首次面世以來,它便被奉為汽車軟件工程師在開發(fā)實踐中的圭臬。
MISRA C++的發(fā)展史
MISRA C++的起源可以追溯到MISRA C標準的成功制定和廣泛應(yīng)用。MISRA C是一套針對C語言的編碼規(guī)范,首次發(fā)布于1998年,它迅速成為汽車行業(yè)中軟件安全性和可靠性的標桿。(回顧MISRA C:2012介紹請見文章
《帶你走近MISRA C:2012》)隨著C++在工業(yè)界的普及,尤其是在汽車電子控制系統(tǒng)中,對C++的類似規(guī)范的需求日益增長?;贛ISRA C的成功經(jīng)驗和市場需求,MISRA組織隨后發(fā)布了適用于C++03標準的編碼規(guī)范MISRA C++:2008。這是首個針對C++語言的MISRA標準,包含一系列的規(guī)則和指導(dǎo)原則,這些規(guī)則覆蓋了從編程實踐到代碼設(shè)計等多個方面,旨在幫助開發(fā)者編寫出更加安全和可靠的代碼。
MISRA C++:2008規(guī)范發(fā)布后,得到了業(yè)界的廣泛認可和采納。它不僅在汽車行業(yè)中得到了應(yīng)用,還擴展到了航空、醫(yī)療設(shè)備和工業(yè)控制等多個領(lǐng)域,并對這些行業(yè)產(chǎn)生了深遠的影響。隨著C++語言標準的不斷更新和新特性的引入,MISRA C++:2008也在經(jīng)歷不斷的修訂和更新,以保持與C++標準語言的同步,并覆蓋新出現(xiàn)的語言特性。MISRA C++:2008與AUTOSAR C++14
但隨著后續(xù)新版本C++標準的發(fā)布,MISRA C++:2008并未將新的C++語言特性納入,于是AUTOSAR組織發(fā)布了AUTOSAR C++14編碼規(guī)范。
AUTOSAR C++14在制定時,大量借鑒了MISRA C++:2008的規(guī)則。MISRA C++:2008是基于C++03標準制定的,而AUTOSAR C++14則是基于更新的C++14標準。AUTOSAR C++14吸收了約91%的MISRA C++:2008規(guī)則,并對其進行了擴展和更新,引入了針對C++11/14特性的規(guī)范。
MISRA C++:2023
MISRA C++:2023發(fā)布于2023年10月,這是MISRA C++的最新版本。它為使用ISO/IEC 1488217) 開發(fā)的安全關(guān)鍵型軟件的組織提供指導(dǎo)。MISRA C++:2023規(guī)則分類
MISRA C++:2023整合了AUTOSAR C++14編碼規(guī)范, 共179條準則。這些規(guī)則按照性質(zhì)分為兩類:Rule(規(guī)則)和Directive(指令),包含175條Rule和4條Directive。規(guī)則有三種不同類別:” Mandatory(強制)”、” Required(要求)”和“Advisory(建議)”, Mandatory類別的規(guī)則中包含5條Rule,Required規(guī)則中包含122條Rule和4條Directive,Advisory規(guī)則中包含48條Rule。
圖1 MISRA C++:2023規(guī)則分類
圖2 MISRA C++:2023規(guī)則類別MISRA C++:2023還引入了MISRA C++的Rule可判定性分類??膳卸ㄐ詤^(qū)分標準為是否能在任何情況下明確回答“該代碼是否遵循了這條規(guī)則?”這個問題。
圖3 Rule的可判定性分類要注意的是,可判定性并不適用于Directive規(guī)則。接下來讓我們進一步了解MISRA C++:2023編碼規(guī)范。
什么是 MISRA C++:2023 Rule 9.5.2,為什么它很重要?MISRA C++:2023 引入了Rule 9.5.2:“ for 范圍初始值設(shè)定項最多應(yīng)包含一個函數(shù)調(diào)用”,以避免在基于范圍的 for 語句的 for 范圍初始值設(shè)定項創(chuàng)建臨時對象時可能發(fā)生的未定義行為。
為了理解為什么會發(fā)生這種情況,讓我們仔細看看基于 C++ 范圍的 for 循環(huán)。
什么是 C++ 中基于范圍的 for 循環(huán)?
在編程中,循環(huán)用于重復(fù)代碼塊。當我們知道要在代碼塊中循環(huán)多少次時會使用for循環(huán)。C++ 基于范圍的 for 循環(huán)是在 C++11 中引入的,作為容器迭代的簡潔表示法。傳統(tǒng)循環(huán)源自 C 語言,具有可選的循環(huán)初始化,然后是循環(huán)條件,最后是循環(huán)增量表達式。
傳統(tǒng)for循環(huán)可用于迭代容器,如下所示:
std::vector v = { "Example", "vector", "of", "strings" };
for ( auto &&i = v.begin(); i != v.end(); ++i ) {
std::cout << *i << “ “;?
}
std::cout << std::endl;?
使用基于范圍的for時,迭代器的使用是隱式的:
for ( auto &&s: v ) {
std::cout << s << “ “;?
}
對于同一循環(huán),這是一個更簡單的表示法。C++ 語言標準指出它是以下方面的縮寫:
{
auto && __range = v;
auto __begin = __range;
auto __end = v.end();
for (; __begin != __end; ++__begin) {
auto &&s = *__begin;
std::cout << s << “ “;?
}
}
但是,這種表示法存在一定的局限性。在上面的示例中, __range 是用 v 初始化的,這是一個更簡單的變量,但也可以使用一個復(fù)雜的表達式,為其創(chuàng)建多個臨時對象。
讓我們考慮使用一個函數(shù),該函數(shù)返回字符串的向量,并具有:?一個輸出用空格分隔的字符串的循環(huán),如上所述;?第二個循環(huán),打印第一個字符串的字母,用空格分隔:
std::vectorcreateStrings() {
return { "Example”, "vector", "of", "strings" };
}
int main() {
for ( auto w: createStrings() ) { std::cout << w << " "; }?
std::cout << std::endl;?
for ( auto c: createStrings()[0] ) { std::cout << c << " "; }?
std::cout << std::endl;?
}
如果我們執(zhí)行此操作,第一個循環(huán)將按預(yù)期運行,但第二個循環(huán)將調(diào)用未定義的行為 。問題是 createStrings()[0] 有兩個函數(shù)調(diào)用。最里面的調(diào)用是 createStrings 的調(diào)用 ,最外面的調(diào)用是對索引運算符[ ]的調(diào)用。
未定義行為的原因是 “ createStrings ”返回的臨時對象 用作“ operator[ ]”調(diào)用的參數(shù),因此,根據(jù) C++ 的規(guī)則,臨時對象的生存期不會延長。
MISRA C++:2023 Rule 9.5.2 如何防范未定義的行為
MISRA C++:2023 Rule 9.5.2 旨在防止這種情況。MISRA C++:2023 引入了規(guī)則 9.5.2,該規(guī)則要求for范圍初始值設(shè)定項最多應(yīng)包含一個函數(shù)調(diào)用。
它還建議通過在循環(huán)范圍之前的單獨聲明中執(zhí)行內(nèi)部函數(shù)調(diào)用來解決此問題。例如:
auto strings = createStrings();
for ( auto c: strings[0] ) { std::cout << c << " "; }?
現(xiàn)在,初始值設(shè)定項中只有一個函數(shù)調(diào)用,因此生存期擴展具有所需的效果,并且行為已完全定義。
-
數(shù)字化
+關(guān)注
關(guān)注
8文章
8445瀏覽量
61536 -
MISRA
+關(guān)注
關(guān)注
0文章
21瀏覽量
6953 -
汽車
+關(guān)注
關(guān)注
13文章
3336瀏覽量
37047
發(fā)布評論請先 登錄
相關(guān)推薦
評論