中文字幕理论片,69视频免费在线观看,亚洲成人app,国产1级毛片,刘涛最大尺度戏视频,欧美亚洲美女视频,2021韩国美女仙女屋vip视频

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開(kāi)通VIP
學(xué)習(xí)MISRAC之六:構(gòu)建安全的編譯環(huán)境——(轉(zhuǎn))

學(xué)習(xí)MISRAC之六:構(gòu)建安全的編譯環(huán)境——(轉(zhuǎn))

 預(yù)處理是編譯環(huán)境處理C 程序的第一個(gè)環(huán)節(jié),但往往最先被程序員忽略。這份看似只是由編譯環(huán)境做的簡(jiǎn)單工作,其實(shí)也是機(jī)關(guān)重重。通過(guò)介紹MISRA C 與預(yù)處理相關(guān)的規(guī)則,希望讀者能夠更準(zhǔn)確地認(rèn)識(shí)編譯器的預(yù)處理過(guò)程,避免出錯(cuò)。無(wú)論是自定義函數(shù)還是由編譯環(huán)境提供的標(biāo)準(zhǔn)庫(kù)函數(shù),如果使用不當(dāng),都會(huì)存在安全隱患。

能不能保證函數(shù)被正確的定義、聲明和調(diào)用,關(guān)乎到整個(gè)程序的成敗。這里介紹MISAR C 中涉及函數(shù)部分有代表性的規(guī)則,并試圖分析制定這些規(guī)則的出發(fā)點(diǎn),以幫助讀者構(gòu)建更為安全的編譯環(huán)境。

1 函數(shù)的定義和聲明

1. 1 在哪里定義
讀者也許會(huì)有這樣的經(jīng)歷:在一個(gè)頭文件中定義了一個(gè)變量,又讓這個(gè)頭文件被多個(gè)源文件引用。這時(shí)編譯器會(huì)“報(bào)怨”說(shuō)重復(fù)定義了同一個(gè)函數(shù)。出錯(cuò)的原因與其說(shuō)是粗心,不如說(shuō)是一個(gè)習(xí)慣的問(wèn)題。

  規(guī)則8. 5 :頭文件中不允許包含對(duì)象或函數(shù)的定義。
  當(dāng)源文件包含某一頭文件時(shí),預(yù)處理器會(huì)將頭文件的內(nèi)容在包含指令處展開(kāi)。顯然,在頭文件中函數(shù)的定義會(huì)在其他源文件中一模一樣的出現(xiàn),導(dǎo)致函數(shù)被重復(fù)定義。解決這一問(wèn)題的關(guān)鍵是明確一個(gè)概念:所有可執(zhí)行的代碼或者對(duì)象和函數(shù)的定義都應(yīng)在. C 的源文件中,頭文件中只能存在其聲明。具體的做法是:為全局變量的聲明增加extern 修飾符,并在相應(yīng)的. C 源文件中定義對(duì)象或函數(shù)。

例如,在Globle. h 文件中僅聲明變量GCounter 。
/ * 在Globle. h 中 * /
extern uint32_t GCounter ;
??
而在. C 文件中定義變量GCounter :
/ * 在GlobleVariables. C 中* /
uint23_t GCounter ;
??
這樣,就可以在所有需要用到全局變量的地方直接引用”Globle. h”頭文件了。不過(guò)也有一些程序員喜歡采取以下的做法:
/ * 在Globle. h 中* /
# ifdef GLOBL ES
# define EXT
# else
# define EXT extern
# endif
EXT uint32_t GCounter ;
??
/ * 在GlobleVariables. C 中* /
# define GLOBL E
# include“Globle. h”
??


/ * 在其他C 文件中* /
# include“Globle. h”
# include“MyLib. h”
  ??
這樣做的好處是只需要維護(hù)“Globle. h”就可以維護(hù)所有全局變量。其他的文件中,直接包含“Globle. h”就可以使用這些全局變量了。上述的兩種做法是等價(jià)的,讀者
可選擇任意一種方式。

1. 2  用好編譯器的檢查功能
在MISRA C 制定關(guān)于函數(shù)編程規(guī)則的背后,有一條很重要的思想:要充分利用編譯器的類型檢查功能來(lái)提高函數(shù)的可靠性。這里的類型檢查包括在函數(shù)定義和調(diào)用時(shí)對(duì)函數(shù)參數(shù)和返回值的類型檢查。

規(guī)則8. 1 :函數(shù)必須聲明原型,在函數(shù)定義和調(diào)用時(shí)原型必須可見(jiàn)。

首先明確一下什么是原型聲明。在科尼漢和里查( K& R) 的著名著作《C 程序設(shè)計(jì)語(yǔ)言(第二版) 》的前言中提到:“C 不是一種強(qiáng)類型語(yǔ)言,但隨著它的發(fā)展,其類型檢
查機(jī)制已得到了加強(qiáng)??在這個(gè)方向上,新的函數(shù)聲明方式是邁出的另外一步。”

這里“新的函數(shù)聲明方式”指的就是原型聲明。原型聲明是標(biāo)準(zhǔn)C 語(yǔ)言中出現(xiàn)的概念,它可以提供更多關(guān)于函數(shù)參數(shù)的信息。在原型聲明中,函數(shù)的參數(shù)要在聲明時(shí)指定參數(shù)名和類型;而非原型聲明,參數(shù)的類型可以缺省,被忽略的參數(shù)聲明默認(rèn)為int 型。

請(qǐng)看下面的聲明:
int f (int i , long j) { ??} (原型聲明)
int f (i ,j) int i ; { ??} (非原型聲明)

要求程序使用原型聲明函數(shù),主要是希望可以利用編譯器檢查函數(shù)調(diào)用時(shí)數(shù)據(jù)類型的一致性。如果調(diào)用函數(shù)時(shí),沒(méi)有進(jìn)行原型聲明,則編譯器不會(huì)檢查出函數(shù)形式參數(shù)與調(diào)用參數(shù)的不一致。請(qǐng)看下面這段程序:
double square (x)
double x ;
{
??
}
調(diào)用時(shí):
long func (i)
long i ;
{  return square (i) ;
}

函數(shù)square () 的形式參數(shù)類型是double 型,但實(shí)際調(diào)用時(shí),調(diào)用參數(shù)是long 類型。因?yàn)闆](méi)有進(jìn)行原型聲明,編譯器不需要對(duì)此給出警告,結(jié)果在沒(méi)有出錯(cuò)信息的情況下,函數(shù)返回了一個(gè)不正確的值。

現(xiàn)在將這段程序改寫為原型聲明:
double square (double x)
{  ?
}
調(diào)用時(shí):
long func (i)
long i ;
{  return square (i) ;
}

這里,編譯器會(huì)檢查出函數(shù)square 的實(shí)際調(diào)用參數(shù)和形式參數(shù)類型不符,并且會(huì)將實(shí)際參數(shù)轉(zhuǎn)換成相應(yīng)的形式參數(shù)的數(shù)據(jù)類型。這樣,參數(shù)i 就在程序員不知情的情況下被編譯器自動(dòng)轉(zhuǎn)換為double 類型,函數(shù)返回正確值。

了解了原型調(diào)用的一些機(jī)制,下面的問(wèn)題就是如何操作才能保證每個(gè)函數(shù)調(diào)用都使用原型調(diào)用,也就是說(shuō),要使原型聲明對(duì)于函數(shù)定義和調(diào)用都“可見(jiàn)”。簡(jiǎn)單的方法是:每一個(gè)外部函數(shù)都在頭文件中有一個(gè)唯一的原型聲明;需要調(diào)用此外部函數(shù)的源文件要包含這一頭文件,保證調(diào)用時(shí)由原型控制(原型對(duì)于“調(diào)用”可見(jiàn)) ;同時(shí),函數(shù)定義所在的源文件也包含這一頭文件,以便編譯器可以檢查原型聲明和其定義相匹配(原型對(duì)于“定義”可見(jiàn)) 。

使用原型調(diào)用除了可以幫助檢查參數(shù)的一致性,還可以使“編譯器產(chǎn)生更為有效的函數(shù)調(diào)用序列”。
為了配合編譯器對(duì)函數(shù)參數(shù)的檢查,程序員應(yīng)牢記規(guī)則16. 1 。

規(guī)則16. 1 :不允許定義參數(shù)數(shù)量不確定的函數(shù)。


標(biāo)準(zhǔn)庫(kù)函數(shù)printf ( ) 深受許多程序員的喜愛(ài),因?yàn)閜rintf () 允許不確定的參數(shù)數(shù)量,用起來(lái)很方便。但是,參數(shù)數(shù)量的不確定很可能會(huì)造成編譯器無(wú)法檢查函數(shù)調(diào)用時(shí)的參數(shù)一致性。對(duì)于像printf () 這種使用廣泛的標(biāo)準(zhǔn)庫(kù)函數(shù),編譯器提供了一些合適的調(diào)用機(jī)制。但程序員必須明確,編譯器無(wú)法保證對(duì)用戶自行定義的參數(shù)數(shù)量不確定的函數(shù)進(jìn)行數(shù)據(jù)類型檢查。因此,MISRA2C 不允許用戶冒險(xiǎn)去定義新的參數(shù)數(shù)量不確定的函數(shù)。

2  函數(shù)的調(diào)用和標(biāo)準(zhǔn)庫(kù)函數(shù)

程序員應(yīng)該清楚,嵌入式應(yīng)用開(kāi)發(fā)中系統(tǒng)的資源往往十分有限,在程序開(kāi)發(fā)上會(huì)有特殊的限制。比如,在RAM空間的使用上往往會(huì)捉襟見(jiàn)肘。像早期的PC 機(jī)程序員一樣,對(duì)RAM 空間的使用可以用“吝惜”來(lái)形容,往往因可以使程序少占用幾個(gè)字節(jié)的RAM 而大做文章。

一個(gè)典型的例子就是遞歸函數(shù)的調(diào)用。遞歸函數(shù)的代碼緊湊,且容易理解,很受C 程序員的推崇。但遞歸函數(shù)的一個(gè)缺點(diǎn)就是:占用RAM(這里主要是指的??臻g)資源太多。對(duì)于嵌入式系統(tǒng)來(lái)說(shuō)這是尤為嚴(yán)重的問(wèn)題。一旦遞歸調(diào)用的層數(shù)過(guò)多,就會(huì)出現(xiàn)??臻g不足的情況。唯一可以避免該情況發(fā)生的方法就是能夠預(yù)先估計(jì)出最大的遞歸調(diào)用層數(shù),從而算出最大??臻g。遺憾的是,很多情況下程序員根本沒(méi)法做出估計(jì),這時(shí)系統(tǒng)中的遞歸函數(shù)成為一個(gè)巨大的隱患。MISRA C 從系統(tǒng)安全角度考慮,選擇了最為安全的做法,不準(zhǔn)使用遞歸調(diào)用。

  規(guī)則16. 2 :函數(shù)不得調(diào)用本身,無(wú)論是直接的調(diào)用,還是間接的調(diào)用。

  一般來(lái)說(shuō),標(biāo)準(zhǔn)庫(kù)函數(shù)是很好用的。它的定義和使用都很清晰,尤其是像printf ( ) 這樣的函數(shù),對(duì)于程序員的調(diào)試工作幫助很大。但某些庫(kù)函數(shù)的使用也可能會(huì)造成問(wèn)題。要盡量安全地使用庫(kù)函數(shù),需要注意三個(gè)方面的問(wèn)題。

①要保證庫(kù)函數(shù)頭文件中的宏、標(biāo)識(shí)符和函數(shù)的定義不受干擾。

  規(guī)則20. 1 :不得定義、重新定義或是取消定義標(biāo)準(zhǔn)函數(shù)庫(kù)中的標(biāo)識(shí)符、宏和函數(shù)。

②要按照正確的方法使用庫(kù)函數(shù)。庫(kù)函數(shù)對(duì)參數(shù)的類型、數(shù)值都有很明確的要求,只有傳遞給庫(kù)函數(shù)正確的參數(shù),才能保證結(jié)果的正確性。
  規(guī)則20. 3 :必須檢查傳遞給庫(kù)函數(shù)的數(shù)值的有效性。

③避免使用可能有問(wèn)題的庫(kù)函數(shù)或者其結(jié)果。比如很多庫(kù)函數(shù)都會(huì)通過(guò)一個(gè)叫做errno 的變量為非零值來(lái)表示執(zhí)行失敗。但是,由于沒(méi)有強(qiáng)制庫(kù)函數(shù)在執(zhí)行成功后將errno 清零,一個(gè)非零的errno 有可能是因?yàn)楫?dāng)前庫(kù)函數(shù)執(zhí)行失敗了,也有可能是因?yàn)橹澳硞€(gè)庫(kù)函數(shù)沒(méi)有正確執(zhí)行。因此,完全依賴errno 來(lái)判斷庫(kù)函數(shù)的執(zhí)行成功與否是不可靠的。

  規(guī)則20. 5 :不得使用錯(cuò)誤指示符errno 。
可能帶來(lái)問(wèn)題的庫(kù)函數(shù)還有很多,MISRA C 為此做了一份總結(jié)。

  規(guī)則20. 4 :不得使用動(dòng)態(tài)堆空間分配。

  規(guī)則20. 6 :不得使用庫(kù)函數(shù)<stddef.h>中的宏offsetof

  規(guī)則20. 7 :不得使用longjmp 函數(shù)中的宏setjmp

  規(guī)則20. 8 :不得使用信號(hào)處理函數(shù)<signal.h >

  規(guī)則20. 9 :不得用輸入/輸出庫(kù)函數(shù)<stdio.h> 來(lái)產(chǎn)生代碼

  規(guī)則20. 10 :不得使用標(biāo)準(zhǔn)庫(kù)<stdlib.h>中的庫(kù)函數(shù)atof 、atoi 和atol

  規(guī)則20. 11 :不得使用標(biāo)準(zhǔn)庫(kù)<stdlib.h>中的庫(kù)函數(shù)abort 、exit 和system

  規(guī)則20. 12 :不得使用標(biāo)準(zhǔn)庫(kù)<time.h>中的時(shí)間處理函數(shù)

3  預(yù)處理———看似簡(jiǎn)單的第一步

預(yù)處理是編譯器處理程序的第一步。預(yù)處理會(huì)在編譯器編譯程序代碼前做一些準(zhǔn)備工作,最為常見(jiàn)的工作是處理文件包和宏定義(分別對(duì)應(yīng)# include 和# define 兩個(gè)
預(yù)處理指令) 。
預(yù)處理器并不對(duì)源代碼做編譯,只是進(jìn)行一些轉(zhuǎn)換工作,例如將文件或宏展開(kāi)等。很多程序員認(rèn)為這種類似復(fù)制、粘貼的活沒(méi)什么了不起,也就放松了對(duì)預(yù)處理工作的檢
查。其實(shí),很多程序的失敗就從這看似簡(jiǎn)單的第一步開(kāi)始。
宏定義是最常見(jiàn)的預(yù)處理指令之一。MISRA C 關(guān)于宏定義有一些很有代表性的規(guī)則。

3. 1  小括號(hào)———一個(gè)也不能少

當(dāng)程序中多處出現(xiàn)同一個(gè)數(shù)值的時(shí)候,程序員就會(huì)想起使用宏。宏定義最大的好處就是使一些常量集中起來(lái),修改其值只需要修改一次,大大提高了程序的可維護(hù)性。
編譯器對(duì)宏的處理原則比較簡(jiǎn)單,宏定義只對(duì)程序文本起作用。一個(gè)經(jīng)典的例子是:
# define abs (x) (x > = 0) x : - x

顯然,程序員希望求變量x 的絕對(duì)值。但是,下面的調(diào)用會(huì)是什么結(jié)果呢?
abs (a - b) ;
展開(kāi)后為(a - b > = 0) a - b : - a - b 。顯然這里的- a - b
并不是程序員想要的結(jié)果,原因是變?cè)獂 兩邊沒(méi)有加小括號(hào)。那么在x 加上括號(hào)以后呢?
# define abs (x) ( (x) > = 0) (x) : - (x)
如果此時(shí)是
abs (a) + 1 ;
展開(kāi)后是(a > = 0) a : - a + 1 ,也不是我們想要的結(jié)果。
看來(lái)還要把整個(gè)宏定義加上括號(hào),這樣才能得到安全可靠的宏定義:
# define abs (x) ( ( (x) > = 0) (x) : - (x) )
為了防止宏展開(kāi)后因缺少括號(hào)而存在的優(yōu)先級(jí)錯(cuò)誤問(wèn)題,MISRA C 有如下規(guī)定。

  規(guī)則19. 10 :在函數(shù)式宏定義中,任何一個(gè)參數(shù)都應(yīng)加上小括號(hào),除非是在# 或# # 運(yùn)算符中。

3. 2  宏定義不是函數(shù)

規(guī)則19. 7 (推薦) :應(yīng)優(yōu)先考慮使用函數(shù)而非函數(shù)式宏定義。

利用類似函數(shù)式的宏定義來(lái)取代函數(shù)調(diào)用,是一個(gè)常用的技巧。這樣做有很多好處,主要是能夠提高程序的運(yùn)行速度。MISRA C 從代碼安全的角度制定這一規(guī)則,主要有兩點(diǎn)考慮。一是宏定義不能像函數(shù)調(diào)用那樣提供參數(shù)類型檢查,錯(cuò)誤的變?cè)愋蜔o(wú)法得到糾正,運(yùn)行的結(jié)果就可能不正確。二是宏定義中的變?cè)赡軙?huì)多次求值,當(dāng)變?cè)磉_(dá)式帶有副作用時(shí),就會(huì)出現(xiàn)問(wèn)題。例如:

# define SQUARE(x) ( (x) 3 (x) )
當(dāng)有如下語(yǔ)句時(shí):
a = 3 ;
b = SQUARE(a + + ) ;

程序員肯定希望得到b = 9 和a = 4 的結(jié)果,可實(shí)際上的結(jié)果卻是b = 12 和a = 5 ,這是為什么呢?
如果考慮到宏展開(kāi)只是做文本的展開(kāi),那么上面的預(yù)處理結(jié)果應(yīng)該是:
a = 3 ;
b = (a + + ) 3 (a + + ) ;
很明顯,這里a + + 運(yùn)行了兩次,運(yùn)行后a = 5 。至于b ,其結(jié)果應(yīng)該是b = 3 ×4 = 12 。
現(xiàn)在,讀者應(yīng)該可以看出來(lái)類似函數(shù)的宏展開(kāi)并不完全和函數(shù)一樣。考慮到系統(tǒng)可靠性是我們所關(guān)注的,上面的工作還不如直接用函數(shù)來(lái)完成。多數(shù)情況下,函數(shù)的運(yùn)
行速度應(yīng)該讓位于其結(jié)果的正確性。
關(guān)于宏定義還有很多有趣的問(wèn)題可以討論,這里就不一一贅述了。

結(jié) 語(yǔ)


至此, 關(guān)于MISRA C: 2004 的學(xué)習(xí)暫告一段落。

MISRA C:2004 有141 條規(guī)則,在6 期的《學(xué)習(xí)園地》欄目中,列舉和解釋了其中有代表性的規(guī)則,大約二分之一,且盡量使每篇文章都能涵蓋MISRA C 規(guī)范的一個(gè)重要方向,以便使讀者了解到MISRA C 的概貌和主導(dǎo)思想。

由于MISRA C:2004 一書中關(guān)于每條規(guī)則的解釋很少,很多例子是在我們理解的基礎(chǔ)上加的,可能存在著錯(cuò)誤或偏差,歡迎大家和我們共同討論。

通過(guò)這6 期介紹,希望大家能夠意識(shí)到:C 是一門并不容易掌握的語(yǔ)言。作為嵌入式工程師,多數(shù)人只是某應(yīng)用領(lǐng)域的專家,對(duì)于C 語(yǔ)言編程,有個(gè)從“業(yè)余”到“專業(yè)”的過(guò)程,學(xué)習(xí)和參考MISRA C 可以幫助他們編寫出更安全、更“專業(yè)”的代碼。尤其對(duì)于一些安全性要求很高的小系統(tǒng),MISRA C 是非常合適的安全編程規(guī)范。這里小系統(tǒng)指開(kāi)發(fā)團(tuán)隊(duì)的規(guī)模小,甚至全部工作都是由一個(gè)人完成的系統(tǒng)。

盡管手冊(cè)式的編程規(guī)范很難引起讀者的興趣,MIS2RA C:2004 還是值得仔細(xì)品味的。經(jīng)驗(yàn)對(duì)于程序員來(lái)說(shuō)是一筆財(cái)富。MISRA C 的編寫專家們大都來(lái)自于汽車工業(yè)及相關(guān)軟件公司,他們有著豐富的汽車安全方面的知識(shí)和軟件開(kāi)發(fā)經(jīng)驗(yàn),MISRA C:2004 很大程度上是他們對(duì)如何提高C 軟件可靠性的經(jīng)驗(yàn)總結(jié)。對(duì)于大多數(shù)程序員來(lái)說(shuō),仔細(xì)研讀這份經(jīng)驗(yàn)總結(jié)可以少走很多彎路,同時(shí)提高自身的編程素養(yǎng)。

目前,“嵌入式”還不是一個(gè)學(xué)科或?qū)I(yè),也許永遠(yuǎn)也不會(huì)是一個(gè)獨(dú)立的學(xué)科。然而,各行各業(yè)都需要嵌入式系統(tǒng),都有義務(wù)推動(dòng)“嵌入式學(xué)科”(如果能這樣表述的話) 的發(fā)展。例如,便攜類應(yīng)用就推動(dòng)了嵌入式系統(tǒng)低功耗技術(shù)的發(fā)展。MISRA C 從汽車工業(yè)軟件可靠性角度,對(duì)C 語(yǔ)言的使用做出種種限制,使之成為汽車工業(yè)的行業(yè)標(biāo)準(zhǔn),并被其他對(duì)可靠性要求高的行業(yè)采納,這是汽車行業(yè)對(duì)嵌入式領(lǐng)域的貢獻(xiàn)。其他行業(yè)的嵌入式工程師也應(yīng)該有責(zé)任、有能力在借鑒其行業(yè)相關(guān)技術(shù)、規(guī)約的基礎(chǔ)上,從不同角度推動(dòng)嵌入式技術(shù)的全面發(fā)展。


參考文獻(xiàn)
[1 ]  MISRA C:2004 , Guidelines for the use of the C language
in critical systems. The Motor Indust ry Software Reliabili2
ty Association ,2004.
[ 2 ]  Kernighan. Brian W, Ritchie. Dennis M. C 程序設(shè)計(jì)語(yǔ)言.
徐寶文譯. 第2 版. 北京:機(jī)械工業(yè)出版社,2001.
[3 ]  Harbison III. Samuel P ,Steele J r. Guy L. C 語(yǔ)言參考手冊(cè).
邱仲潘,等譯. 第5 版. 北京:北京機(jī)械工業(yè)出版社,2003.
[ 4 ]  Les Hatton. The MISRA C Compliance Suite The next
step , Oakwood Computing. http :/ / www. misra c2. com.
[ 5 ]  ISO/ IEC 9899 :1999. International Organization of Standardization , 1999.
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
MISRA C編程規(guī)范標(biāo)準(zhǔn)
MISRA C:讓嵌入式系統(tǒng)更加安全可靠的一些關(guān)鍵規(guī)則
C語(yǔ)言函數(shù)的聲明以及函數(shù)原型
FreeRTOS系列第4篇
C語(yǔ)言頭文件深入理解
FreeBASIC學(xué)習(xí)筆記-包含指令
更多類似文章 >>
生活服務(wù)
熱點(diǎn)新聞
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服