軟件編程規(guī)范(MISRAC)_第1頁
軟件編程規(guī)范(MISRAC)_第2頁
軟件編程規(guī)范(MISRAC)_第3頁
軟件編程規(guī)范(MISRAC)_第4頁
軟件編程規(guī)范(MISRAC)_第5頁
已閱讀5頁,還剩40頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、軟 件 編 程 規(guī) 范目 錄一 環(huán)境二 語言擴(kuò)展三 文檔四 字符集五 標(biāo)識符六 類型七 常量八 聲明與定義九 初始化十 數(shù)值類型轉(zhuǎn)換十一 指針類型轉(zhuǎn)換十二 表達(dá)式十三 控制語句表達(dá)式十四 控制流十五 switch語句十六 函數(shù)十七 指針和數(shù)組十八 結(jié)構(gòu)與聯(lián)合十九 預(yù)處理指令二十 標(biāo)準(zhǔn)庫二十一 運(yùn)行時(shí)錯(cuò)誤一 環(huán)境規(guī)則1.1(強(qiáng)制): 所有代碼都必須遵照ISO 9899:1990 “Programming languages - C”,由ISO/IEC 9899/COR1:1995,ISO/IEC 9899/AMD1:1995,和ISO/IEC9899/COR2:1996 修訂。規(guī)則1.2(強(qiáng)制)

2、: 不能有對未定義行為或未指定行為的依賴性。這項(xiàng)規(guī)則要求任何對未定義行為或未指定行為的依賴,除非在其他規(guī)則中做了特殊說明,都應(yīng)該避免。如果其他某項(xiàng)規(guī)則中聲明了某個(gè)特殊行為,那么就只有這項(xiàng)特定規(guī)則在其需要時(shí)給出背離性。規(guī)則1.3(強(qiáng)制): 多個(gè)編譯器和/或語言只能在為語言/編譯器/匯編器所適合的目標(biāo)代碼定義了通用接口標(biāo)準(zhǔn)時(shí)使用。如果一個(gè)模塊是以非C 語言實(shí)現(xiàn)的或是以不同的C 編譯器編譯的,那么必須要保證該模塊能夠正確地同其他模塊集成。C 語言行為的某些特征依賴于編譯器,于是這些行為必須能夠?yàn)槭褂玫木幾g器所理解。例如:棧的使用、參數(shù)的傳遞和數(shù)據(jù)值的存儲方式(長度、排列、別名、覆蓋,等等)。規(guī)則1.

3、4(強(qiáng)制): 編譯器/鏈接器要確保31 個(gè)有效字符和大小寫敏感能被外部標(biāo)識符支持。ISO 標(biāo)準(zhǔn)要求外部標(biāo)識符的頭6 個(gè)字符是截然不同的。然而由于大多數(shù)編譯器/鏈接器允許至少31 個(gè)有效字符(如同內(nèi)部標(biāo)識符),因此對這樣嚴(yán)格而并不具有幫助性的限制的適應(yīng)性被認(rèn)為是不必要的 。必須檢查編譯器/鏈接器具有這種特性,如果編譯器/鏈接器不能滿足這種限制,就使用編譯器本身的約束。規(guī)則1.5(建議): 浮點(diǎn)應(yīng)用應(yīng)該適應(yīng)于已定義的浮點(diǎn)標(biāo)準(zhǔn)浮點(diǎn)運(yùn)算會(huì)帶來許多問題,一些問題(而不是全部)可以通過適應(yīng)已定義的標(biāo)準(zhǔn)來克服。其中一個(gè)合適的標(biāo)準(zhǔn)是 ANSI/IEEE Std 754 21。同規(guī)則6.3 相一致,浮點(diǎn)類型的定

4、義提供了一個(gè)注釋所用浮點(diǎn)標(biāo)準(zhǔn)的機(jī)會(huì),如:/* IEEE 754 single-precision floating-point */typedef float float32_t;二 語言擴(kuò)展規(guī)則2.1(強(qiáng)制): 匯編語言應(yīng)該被封裝并隔離。在需要使用匯編指令的地方,建議以如下方式封裝并隔離這些指令:(a) 匯編函數(shù)、(b) C函數(shù)、(c) 宏。出于效率的考慮,有時(shí)必須要嵌入一些簡單的匯編指令,如開關(guān)中斷。如果不管出于什么原因需要這樣做,那么最好使用宏來完成。需要注意的是,內(nèi)嵌的匯編語言的使用是對標(biāo)準(zhǔn)C 的擴(kuò)展,因此也需要提出對規(guī)則1.1的背離。#define NOP asm (“ NOP”);

5、規(guī)則2.2(強(qiáng)制): 源代碼應(yīng)該使用 /*/ 類型的注釋。這排除了如 / 這樣C99 類型的注釋和C+類型的注釋,因?yàn)樗贑90 中是不允許的。許多編譯器支持 / 類型的注釋以做為對C90 的擴(kuò)展。預(yù)處理指令(如#define)中 / 的使用可以改變,/*/和/的混合使用也是不一致的。這不僅是類型問題,因?yàn)椴煌木幾g器(在C99之前)可能會(huì)有不同的行為。規(guī)則2.3(強(qiáng)制): 字符序列 /* 不應(yīng)出現(xiàn)在注釋中。C 不支持注釋的嵌套,盡管一些編譯器支持它以做為語言擴(kuò)展。一段注釋以/*開頭,直到第一個(gè)*/為止,在這當(dāng)中出現(xiàn)的任何/*都違反了本規(guī)則。考慮如下代碼段:/* some comment, e

6、nd comment marker accidentally omittedPerform_Critical_Safety_Function (X);/* this comment is not compliant */在檢查包含函數(shù)調(diào)用的頁中,假設(shè)它是可執(zhí)行代碼。因?yàn)榭赡軙?huì)省略掉注釋的結(jié)束標(biāo)記,那么對安全關(guān)鍵函數(shù)的調(diào)用將不會(huì)被執(zhí)行。規(guī)則2.4(建議): 代碼段不應(yīng)被“注釋掉”(comment out)。當(dāng)源代碼段不需要被編譯時(shí),應(yīng)該使用條件編譯來完成(如帶有注釋的#if 或#ifdef 結(jié)構(gòu))。為這種目的使用注釋的開始和結(jié)束標(biāo)記是危險(xiǎn)的,因?yàn)镃 不支持嵌套的注釋,而且已經(jīng)存在于代碼段中的任何

7、注釋將影響執(zhí)行的結(jié)果。三 文檔規(guī)則3.1(強(qiáng)制): 所有實(shí)現(xiàn)定義(implementation-defined)的行為的使用都應(yīng)該文檔化。本規(guī)則要求,任何對實(shí)現(xiàn)定義的行為的依賴這些行為在其他規(guī)則中沒有特別說明的都應(yīng)該寫成文檔,例如對編譯器文檔的參考。如果一個(gè)特定的行為在其他規(guī)則中被顯式說明了,那么只有那項(xiàng)規(guī)則在其需要時(shí)給出背離。完整問題的描述詳見ISO 9899:1990 附錄 G2。規(guī)則3.2(強(qiáng)制): 字符集和相應(yīng)的編碼應(yīng)該文檔化。例如,ISO 10646 22定義了字符集映射到數(shù)字值的國際標(biāo)準(zhǔn)。出于可移植性的考慮,字符常量和字符串只能包含映射到已經(jīng)文檔化的子集中的字符。規(guī)則3.3(建議)

8、: 應(yīng)該確定、文檔化和重視所選編譯器中整數(shù)除法的實(shí)現(xiàn)。當(dāng)兩個(gè)有符號整型數(shù)做除法時(shí),ISO 兼容的編譯器的運(yùn)算可能會(huì)為正或?yàn)樨?fù)。首先,它可能以負(fù)余數(shù)向上四舍五入(如,-5/3 = -1,余數(shù)為-2),或者可能以正余數(shù)向下四舍五入(如,-5/3 = -2,余數(shù)為+1)。重要的是要確定這兩種運(yùn)算中編譯器實(shí)現(xiàn)的是哪一種,并以文檔方式提供給編程人員,特別是第二種情況(通常這種情況比較少)。規(guī)則3.4(強(qiáng)制): 所有#pragma 指令的使用應(yīng)該文檔化并給出良好解釋。這項(xiàng)規(guī)則為本文檔的使用者提供了產(chǎn)生其應(yīng)用中使用的任何pragma 的要求。每個(gè)pragma的含義要寫成文檔,文檔中應(yīng)當(dāng)包含完全可理解的對pr

9、agma 行為及其在應(yīng)用中之含義的充分描述。應(yīng)當(dāng)盡量減少任何pragma 的使用,盡可能地把它們本地化和封裝成專門的函數(shù)。規(guī)則3.5(強(qiáng)制): 如果做為其他特性的支撐,實(shí)現(xiàn)定義(implementation-defined)的行為和位域(bitfields)集合應(yīng)當(dāng)文檔化。這是在使用了規(guī)則6.4 和規(guī)則6.5 中描述的非良好定義的位域時(shí)遇到的特定問題。C 當(dāng)中的位域是該語言中最缺乏良好定義的部分之一。位域的使用可能體現(xiàn)在兩個(gè)主要方面: 為了在大的數(shù)據(jù)類型(同union 一起)中訪問獨(dú)立的數(shù)據(jù)位或成組數(shù)據(jù)位。該用法是不允許的(見規(guī)則 18.4)。 為了訪問用于節(jié)省存儲空間而打包的標(biāo)志(flags

10、)或其他短型(short-length)數(shù)據(jù)。為了有效利用存儲空間而做的短型數(shù)據(jù)的打包,是本文檔所設(shè)想的唯一可接受的位域使用。假定結(jié)構(gòu)元素只能以其名字來訪問,那么程序員就無需設(shè)想結(jié)構(gòu)體中位域的存儲方式。我們建議結(jié)構(gòu)的聲明要保持位域的設(shè)置,并且在同一個(gè)結(jié)構(gòu)中不得包含其他任何數(shù)據(jù)。要注意的是,在定義位域的時(shí)候不需要追隨規(guī)則6.3,因?yàn)樗鼈兊拈L度已經(jīng)定義在結(jié)構(gòu)中了。如果編譯器帶有一個(gè)開關(guān)以強(qiáng)制位域遵循某個(gè)特定的布局,那么它有助于下面的判斷。例如下面可接受的代碼:struct message /* Struct is for bit-fields only */signed int little: 4

11、; /* Note: use of basic types is required */unsigned int x_set: 1;unsigned int y_set: 1;message_chunk;如果要使用位域,就得注意實(shí)現(xiàn)定義的行為所存在的領(lǐng)域及其潛藏的缺陷(意即不可移植性)。特別地,程序員應(yīng)當(dāng)注意如下問題: 位域在存儲單元中的分配是實(shí)現(xiàn)定義(implementation-defined)的,也就是說,它們在存儲單元(通常是一個(gè)字節(jié))中是高端在后(high end)還是低端在后(low end)的。 位域是否重疊了存儲單元的界限同樣是實(shí)現(xiàn)定義的行為(例如,如果順序存儲一個(gè)6位的域和一

12、個(gè)4 位的域,那么4 位的域是全部從新的字節(jié)開始,還是其中2 位占據(jù)一個(gè)字節(jié)中的剩余2 位而其他2 位開始于下個(gè)字節(jié))。規(guī)則3.6(強(qiáng)制): 產(chǎn)品代碼中使用的所有庫都要適應(yīng)本文檔給出的要求,并且要經(jīng)過適當(dāng)?shù)尿?yàn)證。本規(guī)則的對象是產(chǎn)品代碼中的任意庫,因此這些庫可能包含編譯器提供的標(biāo)準(zhǔn)庫、其他第三方的庫或者實(shí)驗(yàn)室中自己開發(fā)的庫。這是由IEC 61508 Part 3 建議的。四 字符集規(guī)則4.1(強(qiáng)制): 只能使用ISO C 標(biāo)準(zhǔn)中定義的escape 序列。參見5.2.2 節(jié)中關(guān)于有效escape 序列的ISO 標(biāo)準(zhǔn)。規(guī)則4.2(強(qiáng)制): 不能使用三字母詞(trigraphs)。三字母詞由2 個(gè)問號

13、序列后跟1 個(gè)確定字符組成(如,?- 代表“”(非)符號,而?)代表“”符號)。它們可能會(huì)對2 個(gè)問號標(biāo)記的其他使用造成意外的混淆,例如字符串“(Date should be in the form ?-?-?)”將不會(huì)表現(xiàn)為預(yù)期的那樣,實(shí)際上它被編譯器解釋為“(Date should be in the form )”五 標(biāo)識符規(guī)則5.1(強(qiáng)制): 標(biāo)識符(內(nèi)部的和外部的)的有效字符不能多于31。ISO 標(biāo)準(zhǔn)要求在內(nèi)部標(biāo)識符之間前31 個(gè)字符必須是不同的以保證可移植性。即使編譯器支持,也不能超出這個(gè)限制。ISO 標(biāo)準(zhǔn)要求外部標(biāo)識符之間前6 個(gè)字符必須是不同的(忽略大小寫)以保證最佳的可移植性

14、。然而這條限制相當(dāng)嚴(yán)格并被認(rèn)為不是必須的。本規(guī)則的意圖是為了在一定程度上放寬ISO 標(biāo)準(zhǔn)的要求以適應(yīng)當(dāng)今的環(huán)境,但應(yīng)當(dāng)確保31 個(gè)字符/大小寫的有效性是可以由實(shí)現(xiàn)所支持的。使用標(biāo)識符名稱要注意的一個(gè)相關(guān)問題是發(fā)生在名稱之間只有一個(gè)字符或少數(shù)字符不同的情況,特別是名稱比較長時(shí),當(dāng)名稱間的區(qū)別很容易被誤讀時(shí)問題就比較顯著,比如1(數(shù)字1)和l(L 的小寫)、0 和O、2 和Z、5 和S,或者n 和h。建議名稱間的區(qū)別要顯而易見。在這問題上的特定方針可以放在風(fēng)格指南中(見4.2.2 節(jié))。規(guī)則5.2(強(qiáng)制): 具有內(nèi)部作用域的標(biāo)識符不應(yīng)使用與具有外部作用域的標(biāo)識符相同的名稱,這會(huì)隱藏了外部標(biāo)識符。外

15、部作用域和內(nèi)部作用域的定義如下。文件范圍內(nèi)的標(biāo)識符可以看做是具有最外部(outermost)的作用域;塊范圍內(nèi)的標(biāo)識符看做是具有更內(nèi)部(more inner)的作用域;連續(xù)嵌套的塊,其作用域更深入。本規(guī)則只是不允許一個(gè)第二深層(second inner)的定義隱藏其外層的定義,如果第二個(gè)定義沒有隱藏第一個(gè)定義,那么就不算違反本規(guī)則。在嵌套的范圍中,使用相同名稱的標(biāo)識符隱藏其他標(biāo)識符會(huì)使得代碼非常混亂。例如:int16_t i;int16_t i; /* This is a different variable */* This is not compliant */i = 3; /* It c

16、ould be confusing as to which I this refers */規(guī)則5.3(強(qiáng)制): typedef 的名字應(yīng)當(dāng)是唯一的標(biāo)識符。typedef 的名稱不能重用,不管是做為其他typedef 或者任何目的。例如:typedef unsigned char uint8_t;typedef unsigned char uint8_t; /* Not compliant redefinition */unsigned char uint8_t; /* Not compliant reuse of uint8_t */typedef 的名稱不能在程序中的任何地方重用。如果類型

17、定義是在頭文件中完成的,而該頭文件被多個(gè)源文件包含,不算違背本規(guī)則。規(guī)則5.4(強(qiáng)制): 標(biāo)簽(tag)名稱必須是唯一的標(biāo)識符。程序中標(biāo)簽的名字不可重用,不管是做為另外的標(biāo)簽還是出于其他目的。ISO 9899:1990 2沒有定義當(dāng)一個(gè)聚合體的聲明以不同形式的類型標(biāo)識符(struct 或union)使用同一個(gè)標(biāo)簽時(shí)的行為。標(biāo)簽的所有使用或者用于結(jié)構(gòu)類型標(biāo)識符,或者用于聯(lián)合類型標(biāo)識符,例如:struct stag uint16_t a; uint16_t b; ;struct stag a1 = 0, 0 ; /* Compliant compatible with above */union

18、stag a2 = 0, 0 ; /* Not compliant not compatible withprevious declarations */void foo (void)struct stag uint16_t a; ; /* Not compliant tag stag redefined */如果類型定義是在頭文件中完成的,且頭文件被多個(gè)源文件包含,那么規(guī)則不算違背。規(guī)則5.5(建議): 具有靜態(tài)存儲期的對象或函數(shù)標(biāo)識符不能重用。不管作用域如何,具有靜態(tài)存儲期的標(biāo)識符都不應(yīng)在系統(tǒng)內(nèi)的所有源文件中重用。它包含帶有外部鏈接的對象或函數(shù),及帶有靜態(tài)存儲類標(biāo)識符的任何對象或函數(shù)。由于

19、編譯器能夠理解這一點(diǎn)而且決不會(huì)發(fā)生混淆,那么對用戶來說就存在著把不相關(guān)的變量以相同名字聯(lián)系起來的可能性。這種混淆的例子之一是,在一個(gè)文件中存在一個(gè)具有內(nèi)部鏈接的標(biāo)識符,而在另外一個(gè)文件中存在著具有外部鏈接的相同名字的標(biāo)識符。規(guī)則5.6(建議): 一個(gè)命名空間中不應(yīng)存在與另外一個(gè)命名空間中的標(biāo)識符拼寫相同的標(biāo)識符,除了結(jié)構(gòu)和聯(lián)合中的成員名字。命名空間與作用域(scope)是不同的,本規(guī)則不考慮作用域。例如,ISO C 允許在一個(gè)作用域內(nèi)為標(biāo)簽(tag)和typedef 使用相同的標(biāo)識符(vector)typedef struct vector ( uint16_t x ; uint16_t y

20、; uint16_t z ; ) vector ;/* Rule violation */ISO C 定義了許多不同的命名空間(見ISO 9899 :1990 6.1.2.3 2)。技術(shù)上,在彼此獨(dú)立的命名空間中使用相同的名字以代表完全不同的項(xiàng)目是可能的,然而由于會(huì)引起混淆,通常不贊成這種做法,因此即使是在獨(dú)立的命名空間中名字也不能重用。下面給出了違背此規(guī)則的例子,其中value 在不經(jīng)意中代替了record.value:struct int16_t key ; int16_t value ; record ;int16_t value; /* Rule violation 2nd use o

21、f value */record.key = 1;value = 0; /* should have been record.value */相比之下,下面的例子沒有違背此規(guī)則,因?yàn)閮蓚€(gè)成員名字不會(huì)引起混淆:struct device_q struct device_q *next ; /* . */ devicesN_DEVICES ;struct task_q struct task_q *next ; /* */ tasksN_TASKS;device0.next = &devices1;tasks0.next = &tasks1;規(guī)則5.7(建議): 不能重用標(biāo)識符名字。不考慮作用域,

22、系統(tǒng)內(nèi)任何文件中不應(yīng)重用標(biāo)識符。本規(guī)則和規(guī)則5.2、5.3、5.4、5.5 和5.6 一同使用。struct air_speeduint16_t speed; /* knots */ *x;struct gnd_speeduint16_t speed; /* mph */* Not Compliant speed is in different units */ *y;x-speed = y-speed;當(dāng)標(biāo)識符名字用在頭文件且頭文件包含在多個(gè)源文件中時(shí),不算違背本規(guī)則。使用嚴(yán)格的命名規(guī)范可以支持本規(guī)則。六 類型規(guī)則6.1(強(qiáng)制): 單純的char 類型應(yīng)該只用做存儲和使用字符值。規(guī)則6.2(

23、強(qiáng)制): signed char 和unsigned char 類型應(yīng)該只用做存儲和使用數(shù)字值。有三種不同的char 類型:(單純的)char、unsigned char、signed char。unsigned char 和signed char 用于數(shù)字型數(shù)據(jù),char 用于字符型數(shù)據(jù)。單純char 類型的符號是實(shí)現(xiàn)定義的,不應(yīng)依賴。單純char 類型所能接受的操作只有賦值和等于操作符(=、=、!=)。規(guī)則6.3(建議): 應(yīng)該使用指示了大小和符號的typedef 以代替基本數(shù)據(jù)類型。不應(yīng)使用基本數(shù)值類型char、int、short、long、float 和doulbe,而應(yīng)使用特定長度(

24、specific-length)的typedef。規(guī)則6.3 幫助我們認(rèn)清存儲類型的大小,卻不能保證可移植性,這是因?yàn)檎麛?shù)提升(integral promotion)的不對稱性。關(guān)于整數(shù)提升的討論,見節(jié)6.10。仍然很重要的是要理解整數(shù)大小的實(shí)現(xiàn)。程序員應(yīng)該注意這些定義之下的typedef 的實(shí)際實(shí)現(xiàn)。比如,本文檔中建議為所有基本數(shù)值類型和字符類型使用如下所示的ISO(POSIX)的typedef。對于32 位計(jì)算機(jī),它們是:typedef char char_t;typedef signed char int8_t;typedef signed short int16_t;typedef s

25、igned 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 是不必要的。規(guī)則6.4(強(qiáng)制): 位域只能被定義為unsigned

26、 int 或singed int 類型。因?yàn)閕nt 類型的位域可以是signed 或unsigned,使用int 是由實(shí)現(xiàn)定義的。由于其行為未被定義,所以不允許為位域使用enum、short 或char 類型。規(guī)則6.5(強(qiáng)制): unsigned int 類型的位域至少應(yīng)該為2 bits 長度。1 bit 長度的有符號位域是無用的。七 常量規(guī)則7.1(強(qiáng)制): 不應(yīng)使用八進(jìn)制常量(零除外)和八進(jìn)制escape 序列。任何以“0”(零)開始的整型常量都被看做是八進(jìn)制的,所以這是危險(xiǎn)的,如在書寫固定長度的常量時(shí)。例如,下面為3 個(gè)數(shù)字位的總線消息做數(shù)組初始化時(shí)將產(chǎn)生非預(yù)期的結(jié)果(052 是八進(jìn)制

27、的,即十進(jìn)制的42):code1 = 109; /* equivalent to decimal 109 */code2 = 100; /* equivalent to decimal 100 */code3 = 052; /* equivalent to decimal 42 */code4 = 071; /* equivalent to decimal 57 */八進(jìn)制的escape 序列是有問題的,這是因?yàn)樵诎诉M(jìn)制escape 結(jié)尾不經(jīng)意引入一個(gè)十進(jìn)制數(shù)會(huì)產(chǎn)生另外一個(gè)字符。下面例子中,第一個(gè)表達(dá)式的值是實(shí)現(xiàn)定義的,因?yàn)槠渥址A堪藘蓚€(gè)字符,“10”和“9”。第二個(gè)字符常量表達(dá)式包含了

28、單一字符“100”,如果字符64不在基本運(yùn)算字符集中,這也將是由實(shí)現(xiàn)定義的。code5 = 109 ; /* implementation-defined, two character constant */code6 = 100 ; /* set to 64, or implementation-defined */最好根本不要使用八進(jìn)制常量或escape 序列,并且要靜態(tài)檢查它們是否出現(xiàn)。整數(shù)常量0(做為單個(gè)數(shù)字書寫的)嚴(yán)格說來是八進(jìn)制常量,然而在此規(guī)則下它也是允許的。八 聲明與定義規(guī)則8.1(強(qiáng)制): 函數(shù)應(yīng)當(dāng)具有原型聲明,且原型在函數(shù)的定義和調(diào)用范圍內(nèi)都是可見的。原型的使用使得編譯器能

29、夠檢查函數(shù)定義和調(diào)用的完整性。如果沒有原型,就不會(huì)迫使編譯器檢查出函數(shù)調(diào)用當(dāng)中的一定錯(cuò)誤(比如,函數(shù)體具有不同的參數(shù)數(shù)目,調(diào)用和定義之間參數(shù)類型的不匹配)。事實(shí)證明,函數(shù)接口是相當(dāng)多問題的肇因,因此本規(guī)則是相當(dāng)重要的。對外部函數(shù)來說,我們建議采用如下方法,在頭文件中聲明函數(shù)(亦即給出其原型),并在所有需要該函數(shù)原型的代碼文件中包含這個(gè)頭文件(見規(guī)則8.8)。為具有內(nèi)部鏈接的函數(shù)給出其原型也是良好的編程實(shí)踐。規(guī)則8.2(強(qiáng)制): 不論何時(shí)聲明或定義了一個(gè)對象或函數(shù),它的類型都應(yīng)顯式聲明。extern x; /* Non-compliant implicit int type */extern i

30、nt16_t x ; /* Compliant explicit type */const y ; /* Non-compliant implicit int type */const int16_t y ; /* Compliant explicit type */static foo (void) ; /* Non-compliant implicit type */static int16_t foo (void) ; /* Compliant explicit type */規(guī)則8.3(強(qiáng)制): 函數(shù)的每個(gè)參數(shù)類型在聲明和定義中必須是等同的,函數(shù)的返回類型也該是等同的。參數(shù)與返回值的類

31、型在原型和定義中必須匹配,這不僅要求等同的基本類型,也要求包含typedef 名稱和限定詞在內(nèi)的類型也要相同。規(guī)則8.4(強(qiáng)制): 如果對象或函數(shù)被聲明了多次,那么它們的類型應(yīng)該是兼容的。兼容類型的定義是冗長復(fù)雜的(詳見ISO 9899 :1990 2,節(jié) 6.1.2.6、6.5.2、6.5.3、6.5.4)。兩個(gè)等同的類型必然是兼容的,而兩個(gè)兼容的類型不需要等同。例如,下面的類型對是兼容的:signed int intchar5 char unsigned short int unsigend short規(guī)則8.5(強(qiáng)制): 頭文件中不應(yīng)有對象或函數(shù)的定義。頭文件應(yīng)該用于聲明對象、函數(shù)、ty

32、pedef 和宏,而不應(yīng)該包含或生成占據(jù)存儲空間的對象或函數(shù)(或它們的片斷)的定義。這樣就清晰地劃分了只有C 文件才包含可執(zhí)行的源代碼,而頭文件只能包含聲明。規(guī)則8.6(強(qiáng)制): 函數(shù)應(yīng)該聲明為具有文件作用域。在塊作用域中聲明函數(shù)會(huì)引起混淆并可能導(dǎo)致未定義的行為。規(guī)則8.7(強(qiáng)制): 如果對象的訪問只是在單一的函數(shù)中,那么對象應(yīng)該在塊范圍內(nèi)聲明。可能的情況下,對象的作用域應(yīng)該限制在函數(shù)內(nèi)。只有當(dāng)對象需要具有內(nèi)部或外部鏈接時(shí)才能為其使用文件作用域。當(dāng)在文件范圍內(nèi)聲明對象時(shí),使用規(guī)則8.10。良好的編程實(shí)踐是,在不必要的情況下避免使用全局標(biāo)識符。對象聲明在最外層或最內(nèi)層的做法主要是種風(fēng)格問題。規(guī)則

33、8.8(強(qiáng)制): 外部對象或函數(shù)應(yīng)該聲明在唯一的文件中。通常這意味著在一個(gè)頭文件中聲明一個(gè)外部標(biāo)識符,而在定義或使用該標(biāo)識符的任何文件中包含這個(gè)頭文件。例如,在頭文件featureX.h 中聲明:extern int16_t a ;然后對a 進(jìn)行定義:#include int16_t a = 0 ;工程中存在的頭文件可能是一個(gè)或多個(gè),但是任何一個(gè)外部對象或函數(shù)都只能在一個(gè)頭文件中聲明。規(guī)則8.9(強(qiáng)制): 具有外部鏈接的標(biāo)識符應(yīng)該具有準(zhǔn)確的外部定義。一個(gè)標(biāo)識符如果存在多個(gè)定義(在不同的文件中)或者甚至沒有定義,那么其行為是未經(jīng)定義的。不同文件中的多個(gè)定義是不允許的,即使這些定義相同也不允許;進(jìn)

34、而如果這些定義不同或者標(biāo)識符的初始值不同,問題顯然很嚴(yán)重。規(guī)則8.10(強(qiáng)制): 在文件范圍內(nèi)聲明和定義的所有對象或函數(shù)應(yīng)該具有內(nèi)部鏈接,除非是在需要外部鏈接的情況下。如果一個(gè)變量只是被同一文件中的函數(shù)所使用,那么就用static。類似地,如果一個(gè)函數(shù)只是在同一文件中的其他地方調(diào)用,那么就用static。使用static 存儲類標(biāo)識符將確保標(biāo)識符只是在聲明它的文件中是可見的,并且避免了和其他文件或庫中的相同標(biāo)識符發(fā)生混淆的可能性。規(guī)則8.11(強(qiáng)制): static 存儲類標(biāo)識符應(yīng)該用于具有內(nèi)部鏈接的對象和函數(shù)的定義和聲明。static 和extern 存儲類標(biāo)識符常常是產(chǎn)生混淆的原因。良好的

35、編程習(xí)慣是,把static 關(guān)鍵字一致地應(yīng)用在所有具有內(nèi)部鏈接的對象和函數(shù)的聲明上。規(guī)則8.12(強(qiáng)制): 當(dāng)一個(gè)數(shù)組聲明為具有外部鏈接,它的大小應(yīng)該顯式聲明或者通過初始化進(jìn)行隱式定義。int array110 ; /* Compliant */extern int array2 ; /* Not compliant */int array2 = 0, 10, 15 ; /* Compliant */盡管可以在數(shù)組聲明不完善時(shí)訪問其元素,然而仍然是在數(shù)組的大小可以顯式確定的情況下,這樣做才會(huì)更為安全。九 初始化規(guī)則9.1(強(qiáng)制): 所有自動(dòng)變量在使用前都應(yīng)被賦值。本規(guī)則的意圖是使所有變量在其被

36、讀之前已經(jīng)寫過了,除了聲明中的初始化。注意,根據(jù)ISO C 標(biāo)準(zhǔn),具有靜態(tài)存儲期的變量缺省地被自動(dòng)賦予零值,除非經(jīng)過了顯式的初始化。實(shí)際中,一些嵌入式環(huán)境沒有實(shí)現(xiàn)這樣的缺省行為。靜態(tài)存儲期是所有以static存儲類形式聲明的變量或具有外部鏈接的變量的共同屬性,自動(dòng)存儲期變量通常不是自動(dòng)初始化的。規(guī)則9.2(強(qiáng)制): 應(yīng)該使用大括號以指示和匹配數(shù)組和結(jié)構(gòu)的非零初始化構(gòu)造。ISO C 要求數(shù)組、結(jié)構(gòu)和聯(lián)合的初始化列表要以一對大括號括起來(盡管不這樣做的行為是未定義的)。本規(guī)則更進(jìn)一步地要求,使用附加的大括號來指示嵌套的結(jié)構(gòu)。它迫使程序員顯式地考慮和描述復(fù)雜數(shù)據(jù)類型元素(比如,多維數(shù)組)的初始化次序

37、。例如,下面的例子是二維數(shù)組初始化的有效(在ISO C 中)形式,但第一個(gè)與本規(guī)則相違背:int16_t y32 = 1, 2, 3, 4, 5, 6 ; /* not compliant */int16_t y32 = 1, 2 , 3, 4 , 5, 6 ; /* compliant */在結(jié)構(gòu)中以及在結(jié)構(gòu)、數(shù)組和其他類型的嵌套組合中,規(guī)則類似。還要注意的是,數(shù)組或結(jié)構(gòu)的元素可以通過只初始化其首元素的方式初始化(為0 或NULL)。如果選擇了這樣的初始化方法,那么首元素應(yīng)該被初始化為0(或NULL),此時(shí)不需要使用嵌套的大括號。ISO 標(biāo)準(zhǔn) 2 包含了更多的初始化例子。規(guī)則9.3(強(qiáng)制):

38、 在枚舉列表中,“=”不能顯式用于除首元素之外的元素上,除非所有的元素都是顯式初始化的。如果枚舉列表的成員沒有顯式地初始化,那么C 將為其分配一個(gè)從0 開始的整數(shù)序列,首元素為0,后續(xù)元素依次加1。如上規(guī)則允許的,首元素的顯式初始化迫使整數(shù)的分配從這個(gè)給定的值開始。當(dāng)采用這種方法時(shí),重要的是確保所用初始化值一定要足夠小,這樣列表中的后續(xù)值就不會(huì)超出該枚舉常量所用的int 存儲量。列表中所有項(xiàng)目的顯式初始化也是允許的,它防止了易產(chǎn)生錯(cuò)誤的自動(dòng)與手動(dòng)分配的混合。然而,程序員就該擔(dān)負(fù)職責(zé)以保證所有值都處在要求的范圍內(nèi)以及值不是被無意復(fù)制的。enum colour red = 3, blue, gre

39、en, yellow = 5 ; /* not compliant */* green and yellow represent the same value this is duplication */enum colour red = 3, blue = 4, green = 5, yellow = 5 ; /* compliant */* green and yellow represent the same value this is duplication */十 數(shù)值類型轉(zhuǎn)換規(guī)則10.1(強(qiáng)制): 下列條件成立時(shí),整型表達(dá)式的值不應(yīng)隱式轉(zhuǎn)換為不同的基本類型:a) 轉(zhuǎn)換不是帶符號的向

40、更寬整數(shù)類型的轉(zhuǎn)換,或者b) 表達(dá)式是復(fù)雜表達(dá)式,或者c) 表達(dá)式不是常量而是函數(shù)參數(shù),或者d) 表達(dá)式不是常量而是返回的表達(dá)式。規(guī)則10.2(強(qiáng)制): 下列條件成立時(shí),浮點(diǎn)類型表達(dá)式的值不應(yīng)隱式轉(zhuǎn)換為不同的類型:a) 轉(zhuǎn)換不是向更寬浮點(diǎn)類型的轉(zhuǎn)換,或者b) 表達(dá)式是復(fù)雜表達(dá)式,或者c) 表達(dá)式是函數(shù)參數(shù),或者d) 表達(dá)式是返回表達(dá)式。還要注意,在描述整型轉(zhuǎn)換時(shí),始終關(guān)注的是基本類型而非真實(shí)類型。這兩個(gè)規(guī)則廣泛地封裝了下列原則: 有符號和無符號之間沒有隱式轉(zhuǎn)換 整型和浮點(diǎn)類型之間沒有隱式轉(zhuǎn)換 沒有從寬類型向窄類型的隱式轉(zhuǎn)換 函數(shù)參數(shù)沒有隱式轉(zhuǎn)換 函數(shù)的返回表達(dá)式?jīng)]有隱式轉(zhuǎn)換 復(fù)雜表達(dá)式?jīng)]有隱式

41、轉(zhuǎn)換限制復(fù)雜表達(dá)式的隱式轉(zhuǎn)換的目的,是為了要求在一個(gè)表達(dá)式里的數(shù)值運(yùn)算序列中,所有的運(yùn)算應(yīng)該準(zhǔn)確地以相同的數(shù)值類型進(jìn)行。注意這并不是說表達(dá)式中的所有操作數(shù)必須具備相同的類型。表達(dá)式u32a + u16b + u16c 是合適的兩個(gè)加法在概念上(notionally)都以U32 類型進(jìn)行表達(dá)式u16a + u16b + u32c 是不合適的第一個(gè)加法在概念上以U16 類型進(jìn)行,第二個(gè)加法是U32 類型的。使用名詞“在概念上”是因?yàn)?,在?shí)際中數(shù)值運(yùn)算的類型將依賴于int 實(shí)現(xiàn)的大小。通過遵循這樣的原則,所有運(yùn)算都以一致的(基本)類型來進(jìn)行,能夠避免程序員產(chǎn)生的混淆和與整數(shù)提升有關(guān)的某些危險(xiǎn)。規(guī)則1

42、0.3(強(qiáng)制): 整型復(fù)雜表達(dá)式的值只能強(qiáng)制轉(zhuǎn)換到更窄的類型且與表達(dá)式的基本類型具有相同的符號。規(guī)則10.4(強(qiáng)制): 浮點(diǎn)類型復(fù)雜表達(dá)式的值只能強(qiáng)制轉(zhuǎn)換到更窄的浮點(diǎn)類型。如果強(qiáng)制轉(zhuǎn)換要用在任何復(fù)雜表達(dá)式上,可以應(yīng)用的轉(zhuǎn)換的類型應(yīng)該嚴(yán)格限制。如6.10節(jié)所闡釋的,復(fù)雜表達(dá)式的轉(zhuǎn)換經(jīng)常是混淆的來源,保持謹(jǐn)慎是明智的做法。為了符合這些規(guī)則,有必要使用臨時(shí)變量并引進(jìn)附加的語句。 (float32_t) (f64a + f64b) /* compliant */ (float64_t) (f32a + f32b) /* not compliant */ (float64_t) f32a /* comp

43、liant */ (float64_t) (s32a / s32b) /* not compliant */ (float64_t) (s32a s32b) /* not compliant */ (float64_t) s32a / (float32_t) s32b /* compliant */ (uint32_t) (u16a + u16b) /* not compliant */ (uint32_t) u16a + u16b /* compliant */. (uint32_t) u16a + (uint32_t) u16b /* compliant */. (int16_t) (s3

44、2a 12345) /* compliant */. (uint8_t) (u16a * u16b) /* compliant */. (uint16_t) (u8a * u8b) /* not compliant */. (int16_t) (s32a * s32b) /* compliant */. (int32_t) (s16a * s16b) /* not compliant */ (uint16_t) (f64a + f64b) /* not compliant */ (float32_t) (u16a + u16b) /* not compliant */ (float64_t)

45、foo1 (u16a + u16b) /* compliant */ (int32_t) buf16au16a + u16b /* compliant */規(guī)則10.5(強(qiáng)制): 如果位運(yùn)算符 和 應(yīng)用在基本類型為unsigned char 或unsignedshort 的操作數(shù),結(jié)果應(yīng)該立即強(qiáng)制轉(zhuǎn)換為操作數(shù)的基本類型。當(dāng)這些操作符(和 4; /* not compliant */port 的值在16 位機(jī)器上是0xffa5,而在32 位機(jī)器上是0xffffffa5。在每種情況下,result的值是0xfa,然而期望值可能是0x0a。這樣的危險(xiǎn)可以通過如下所示的強(qiáng)制轉(zhuǎn)換來避免:result_8

46、 = ( ( uint8_t ) (port ) ) 4; /* compliant */result_16 = ( ( uint16_t ) (uint16_t) port ) ) 4 ; /* compliant */規(guī)則10.6(強(qiáng)制): 后綴“U”應(yīng)該用在所有unsigned 類型的常量上。整型常量的類型是混淆的潛在來源,因?yàn)樗蕾囉谠S多因素的復(fù)雜組合,包括: 常數(shù)的量級 整數(shù)類型實(shí)現(xiàn)的大小 任何后綴的存在 數(shù)值表達(dá)的進(jìn)制(即十進(jìn)制、八進(jìn)制或十六進(jìn)制)例如,整型常量“40000”在32 位環(huán)境中是int 類型,而在16 位環(huán)境中則是long 類型。值0x8000 在16 位環(huán)境中是un

47、signed int 類型,而在32 位環(huán)境中則是(signed)int 類型。注意: 任何帶有“U”后綴的值是unsigned 類型 一個(gè)不帶后綴的小于231 的十進(jìn)制值是signed 類型但是: 不帶后綴的大于或等于215 的十六進(jìn)制數(shù)可能是signed 或unsigned 類型 不帶后綴的大于或等于231 的十進(jìn)制數(shù)可能是signed 或unsigned 類型常量的符號應(yīng)該明確。符號的一致性是構(gòu)建良好形式的表達(dá)式的重要原則。如果一個(gè)常數(shù)是unsigned 類型,為其加上“U”后綴將有助于避免混淆。當(dāng)用在較大數(shù)值上時(shí),后綴也許是多余的(在某種意義上它不會(huì)影響常量的類型);然而后綴的存在對代

48、碼的清晰性是種有價(jià)值的幫助。十一 指針類型轉(zhuǎn)換指針類型可以歸為如下幾類: 對象指針 函數(shù)指針 void 指針 空(null)指針常量(即由數(shù)值0 強(qiáng)制轉(zhuǎn)換為void*類型)涉及指針類型的轉(zhuǎn)換需要明確的強(qiáng)制,除非在以下時(shí)刻: 轉(zhuǎn)換發(fā)生在對象指針和void 指針之間,而且目標(biāo)類型承載了源類型的所有類型標(biāo)識符 當(dāng)空指針常量(void*)被賦值給任何類型的指針或與其做等值比較時(shí),空指針常量被自動(dòng)轉(zhuǎn)化為特定的指針類型C 當(dāng)中只定義了一些特定的指針類型轉(zhuǎn)換,而一些轉(zhuǎn)換的行為是實(shí)現(xiàn)定義的。規(guī)則11.1(強(qiáng)制): 轉(zhuǎn)換不能發(fā)生在函數(shù)指針和其他除了整型之外的任何類型指針之間。函數(shù)指針到不同類型指針的轉(zhuǎn)換會(huì)導(dǎo)致未

49、定義的行為。舉個(gè)例子,這意味著一個(gè)函數(shù)指針不能轉(zhuǎn)換成指向不同類型函數(shù)的指針。規(guī)則11.2(強(qiáng)制): 對象指針和其他除整型之外的任何類型指針之間、對象指針和其他類型對象的指針之間、對象指針和void 指針之間不能進(jìn)行轉(zhuǎn)換。這些轉(zhuǎn)換未經(jīng)定義。規(guī)則11.3(建議): 不應(yīng)在指針類型和整型之間進(jìn)行強(qiáng)制轉(zhuǎn)換當(dāng)指針轉(zhuǎn)換到整型時(shí)所需要的整型的大小是實(shí)現(xiàn)定義的。盡可能的情況下要避免指針和整型之間的轉(zhuǎn)換,但是在訪問內(nèi)存映射寄存器或其他硬件特性時(shí)這是不可避免的。規(guī)則11.4(建議): 不應(yīng)在某類型對象指針和其他不同類型對象指針之間進(jìn)行強(qiáng)制轉(zhuǎn)換。如果新的指針類型需要更嚴(yán)格的分配時(shí)這樣的轉(zhuǎn)換可能是無效的。uint8_t * p1;uint32_t * p2;p2

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論