色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

嵌入式C語言的自我修養(yǎng):這樣編出來的代碼簡直行云流水!

j4AI_wujianying ? 來源:單片機精講吳鑒鷹 ? 2020-05-14 14:43 ? 次閱讀

0 規(guī)范制定說明

0.1 箴言

技術(shù)人員設(shè)計程序的首要目的是用于技術(shù)人員溝通和交流,其次才是用于機器執(zhí)行。程序的生命力在于用戶使用,程序的成長在于后期的維護及根據(jù)用戶需求更新和升級功能。

如果你的程序只能由你來維護,當你離開這個程序時,你的程序也和你一起離開了,這將給公司和后來接手的技術(shù)人員帶來巨大的痛苦和損失。

因此,為了程序可讀、易理解、好維護,你的程序需要遵守一定的規(guī)范,你的程序需要設(shè)計。

“程序必須為閱讀它的人而編寫,只是順便用于機器執(zhí)行。”

—— Harold Abelson 和 Gerald Jay Sussman

“編寫程序應(yīng)該以人為本,計算機第二。”

—— Steve McConnell

0.1 簡介

為提高產(chǎn)品代碼質(zhì)量,指導儀表嵌入式軟件開發(fā)人員編寫出簡潔、可維護、可靠、可測試、高效、可移植的代碼,編寫了本規(guī)范。

本規(guī)范將分為完整版和精簡版,完整版將包括更多的樣例、規(guī)范的解釋以及參考材料(what & why),而精簡版將只包含規(guī)則部分(what)以便查閱。

在本規(guī)范的最后,列出了一些業(yè)界比較優(yōu)秀的編程規(guī)范,作為延伸閱讀參考材料。

本規(guī)范主要包含以下兩個方面的內(nèi)容:

一:為形成統(tǒng)一編程規(guī)范,從編碼形式角度出發(fā),本規(guī)范對標示符命名、格式與排版、注釋等方面進行了詳細闡述。

二:為編寫出高質(zhì)量嵌入式軟件,從嵌入式軟件安全及可靠性出發(fā),本規(guī)范對由于C語言標準、C語言本身、C編譯器及個人理解導致的潛在危險進行說明及規(guī)避。

0.3 適用范圍

本規(guī)范適用于XXX股份有限公司儀表臺秤產(chǎn)品部嵌入式軟件的開發(fā),也對其他嵌入式軟件開發(fā)起一定的指導作用。

0.4 術(shù)語定義

0.4.1規(guī)范術(shù)語

原則:編程時必須堅持的指導思想。

規(guī)則:編程時需要遵循的約定,分為強制和建議(強制是必須遵守的,建議是一般情況下需要遵守,但沒有強制性)。

說明:對原則/規(guī)則進行必要的解釋。

實例:對此原則/規(guī)則從正、反兩個方面給出例子。

材料:擴展、延伸的閱讀材料。

Unspecified:未詳細說明的行為,這些是必須成功編譯的語言結(jié)構(gòu),但關(guān)于結(jié)構(gòu)的行為,編譯器的編寫者有某些自由。例如C語言中的“運算次序”問題。這樣的問題有 22 個。

在某種方式上完全相信編譯器的行為是不明智的。編譯器的行為甚至不會在所有可能的結(jié)構(gòu)中都是一致的。

Undefined:未定義行為,這些是本質(zhì)的編程錯誤,但編譯器的編寫者不一定為此給出錯誤信息。相應(yīng)的例子是無效參數(shù)傳遞給函數(shù),或函數(shù)的參數(shù)與定義時的參數(shù)不匹配。從安全性角度這是特別重要的問題,因為它們代表了那些不一定能被編譯器捕捉到的錯誤。

Implementation-defined:實現(xiàn)定義的行為,這有些類似于“unspecified ”問題,其主要區(qū)別在于編譯器要提供一致的行為并記錄成文檔。換句話說,不同的編譯器之間功能可能會有不同,使得代碼不具有可移植性,但在任一編譯器內(nèi),行為應(yīng)當是良好定義的。

比如用在一個正整數(shù)和一個負整數(shù)上的整除運算“/ ”和求模運算符“% ”。存在76個這樣的問題。

從安全性角度,假如編譯器完全地記錄了它的方法并堅持它的實現(xiàn),那么它可能不是那樣至關(guān)重要。盡可能的情況下要避免這些問題。

0.4.2 C語言相關(guān)術(shù)語

聲明(declaration):指定了一個變量的標識符,用來描述變量的類型,是類型還是對象,函數(shù)等。聲明,用于編譯器(compiler)識別變量名所引用的實體。以下這些就是聲明:

externintbar; externintg(int,int); doublef(int,double);[ 對于函數(shù)聲明,extern關(guān)鍵字是可以省略的 。]

定義(definition):是對聲明的實現(xiàn)或者實例化。連接器(linker)需要它(定義)來引用內(nèi)存實體。

與上面的聲明相應(yīng)的定義如下:

intbar; intg(intlhs,intrhs) { returnlhs*rhs; } doublef(inti,doubled){ returni+d; }

0.5 規(guī)則的形式

規(guī)則/原則<序號>(規(guī)則類型):規(guī)則內(nèi)容。

[原始參考]

<序號>:每條規(guī)則都有一個序號,序號是按照章節(jié)目錄-**的形式,從數(shù)字1開始。例如,若在此章節(jié)有個規(guī)則的話,序號為0.5-1。

(規(guī)則類型):或者是‘強制’,或者是‘建議’。

規(guī)則內(nèi)容:此條規(guī)則的具體內(nèi)容。

[原始參考]:指示了產(chǎn)生本條款或本組條款的可應(yīng)用的主要來源。

1 標示符命名規(guī)則

1.1 標示符命名總則

規(guī)則1.1-1(強制):標識符(內(nèi)部的和外部的)的有效字符不能多于31。

[UndefinedImplementation-defined]

說明:ISO 標準要求在內(nèi)部標識符之間前31 個字符必須是不同的,外部標識符之間前6 個字符必須是不同的(忽略大小寫)以保證可移植性。我們這里放寬了此要求,要求內(nèi)部、外部標示符的有效字符不能多于31即可。

這樣主要是便于編譯器識別,代碼清晰易讀,并保證可移植性。

規(guī)則1.1-2(強制):具有內(nèi)部作用域的標識符不應(yīng)使用與具有外部作用域的標識符相同的名稱,在內(nèi)部作用域里具有內(nèi)部標示符會隱藏外部標識符。

說明:外部作用域和內(nèi)部作用域的定義如下。文件范圍內(nèi)的標識符可以看做是具有最外部(outermost )的作用域;塊范圍內(nèi)的標識符看做是具有更內(nèi)部(more inner)的作用域,連續(xù)嵌套的塊,其作用域更深入。如果內(nèi)部作用域標示符和外部作用域標示符同名,內(nèi)部作用域標示符會覆蓋外部作用域標示符,導致程序混亂。

實例:

INT8Utest; { INT8Utest;/*定義了兩個test*/ test=3;/*這將產(chǎn)生混淆*/ }

規(guī)則1.1-3(建議):具有靜態(tài)存儲期的對象或函數(shù)標識符不能重用。

說明:不管作用域如何,具有靜態(tài)存儲期的標識符都不應(yīng)在系統(tǒng)內(nèi)的所有源文件中重用。它包含帶有外部鏈接的對象或函數(shù),及帶有靜態(tài)存儲類標識符的任何對象或函數(shù)。

在一個文件中存在一個具有內(nèi)部鏈接的標識符,而在另外一個文件中存在著具有外部鏈接的相同名字的標識符,或者存在兩個標示符相同的外部標示符。對用戶來說,這有可能導致混淆。

實例:

test1.c

/**定義了一個靜態(tài)文件域變量test1*/ staticINT8Utest1; voidtest_fun(void) { INT8Utest1;/*定義了一個同名的局部變量test1*/ }

test2.c

/**在另一個文件又定義了一個具有外部鏈接的文件域變量test1*/ INT8Utest1;

原則1.1-4(強制):標識符的命名要清晰、明了,有明確含義,同時使用完整的單詞或大家基本可以理解的縮寫,避免使人產(chǎn)生誤解。

說明:標示符的命名盡量做到見名知意,盡量讓別人快速理解你的代碼。

實例:

好的命名方法:

INT8U debug_message ;

INT16U err_num ;

不好的命名方法:

INT8U dbmesg ;

INT16U en ;

原則1.1-5(強制):常見通用的單詞縮寫盡量統(tǒng)一,不得使用漢語拼音、英語混用。

說明:簡短的單詞可以使用略去‘元音’字母形成縮寫,較長的單詞可以使用音節(jié)首字母單詞前幾個字母形成縮寫,針對大家公認的單詞縮寫要統(tǒng)一。對于特定的項目要使用的專有縮寫應(yīng)該注明或者做統(tǒng)一說明。

實例:

常見單詞縮寫表(建議):

單詞 縮寫 單詞 縮寫
argument arg buffer buf
clock clk command cmd
compare cmp configuration cfg
device dev error err
hexadecimal hex increment inc
initialize init maximum max
message msg minimum min
parameter param previous prev
register reg semaphore sem
statistic stat synchronize syn
temp tmp

原則1.1-6(建議):用正確的反義詞組命名具有互斥意義的變量或相反動作的函數(shù)等。

實例:常見反義詞表:

正義 反義 正義 反義
add remove begin end
create destroy insert delete
first last get release
increment decrement put get
add delete lock unlock
open close min max
old new start stop
next previous source target
show hide send receive
source destination copy pase
up down

原則1.1-7(建議):標示符盡量避免使用數(shù)字編號,除非邏輯上需要。

實例:

#defineDEBUG_0_MSG #defineDEBUG_1_MSG 應(yīng)改為更有意義的定義: #defineDEBUG_WARN_MSG #defineDEBUG_ERR_MSG

參考材料:《代碼大全第2版》(Steve McConnell 著 金戈/湯凌/陳碩/張菲 譯 電子工業(yè)出版社2006年3月)"第11章變量命的力量"。

1.2 文件命名及存儲規(guī)則

規(guī)則1.2-1(強制):文件名使用小寫字母。

說明:由于不同系統(tǒng)對文件名大小寫處理不同,Windows不區(qū)分文件名大小寫,而Linux區(qū)分。所以文件名命名均采用小寫字母,多個單詞之間可使用”_”分隔符。

實例:disp.h os_sem.c

規(guī)則1.2-2(建議):工程源碼使用GB2312編碼方式。

說明:程序里的注釋可能會使用中文,GB2312是簡體中文編碼,大部分的編輯工具和集成IDE環(huán)境都支持GB2312編碼,為避免中文亂碼,建議使用GB2312對源碼進行編碼。若需要轉(zhuǎn)換成其他編碼格式,可使用文本編碼轉(zhuǎn)換工具進行轉(zhuǎn)換。

規(guī)則1.2-3(強制):工程源碼使用版本管理工具進行版本管理。

說明:程序一般需要大量更新、修正、維護工作,且有時需要多人合作。使用版本管理工具可以幫助你提高工作效率。建議使用“Git”版本管理工具。

1.3 變量命名規(guī)則

原則1.3-1(強制):變量命名應(yīng)明確所代表的含義或者狀態(tài)。

說明:變量名稱可以使用名詞表述清楚的盡量使用名詞,使用名詞無法描述清楚時,使用形容詞或者描述性的單詞+名詞的形式。變量一般為實體的屬性、狀態(tài)等信息,使用上述方案一般可以解決變量名的命名問題,如果出現(xiàn)命名很困難或者無法給出合理的命名方式時,問題可能出現(xiàn)在整體設(shè)計上,請重新審視設(shè)計。

規(guī)則1.3-2(強制):全局變量添加”G_”前綴,全局靜態(tài)變量添加” S_ ”,局部靜態(tài)變量添加”s_”前綴。使用大小寫混合方式命名,大寫字母用于分割不同單詞。

說明:添加前綴的原因有兩個。首先,使全局變量變得更醒目,提醒技術(shù)開發(fā)人員使用這些變量時要小心。其次,添加前綴使全局變量和靜態(tài)變量變得和其他變量不一致,提醒技術(shù)開發(fā)人員盡量少用全局變量。

實例:

/**出錯信息*/ INT8UG_ErrMsg; /**每秒鐘轉(zhuǎn)動圈數(shù)*/ staticINT32US_CirclePerSec;

規(guī)則1.3-3(強制):局部變量使用小寫字母,若標示符比較復雜,使用’_’分隔符。

說明:局部變量全部使用小寫字母,和全局變量有明顯區(qū)分,使讀者看到標示符就知道是何種作用域的變量。

實例:

INT32Udownload_program_address;

規(guī)則1.3-4(強制):定義指針變量*緊挨變量名,全局指針變量使用大寫P前綴”P_”,局部指針變量使用小寫p前綴”p _”。

實例:

INT8U*P_MsgAddress;/*全局變量*/ INT8U*p_msg;/*局部變量*/

1.4 函數(shù)命名規(guī)則

原則1.4-1(強制):函數(shù)命名應(yīng)該明確針對什么對象做出了什么操作。

說明:函數(shù)的功能是獲取、修改實體的屬性、狀態(tài)等,采用“動詞+名詞”的方式可以滿足上述需求,若出現(xiàn)使用此方式命名函數(shù)很困難或不能命名的情況,問題可能出現(xiàn)在整體設(shè)計上,請重新審視設(shè)計方案。

規(guī)則1.4-2(強制):具有外部鏈接的函數(shù)命名使用大小寫混合的方式,首字母大寫,用于分割不同單詞。

說明:函數(shù)具有外部鏈接屬性的含義是函數(shù)通過頭文件對外聲明后,對其他文件或模塊來說是可見的。如果一個函數(shù)要在其他模塊或者文件中使用,需要在頭文件中聲明該函數(shù)。另外,在頭文件聲明函數(shù),還可以促使編譯器檢查函數(shù)聲明和調(diào)用的一致性。

實例:

char*GetErrMsg(ErrMsg*msg);

規(guī)則1.4-3(強制):具有文件內(nèi)部鏈接屬性的函數(shù)命名使用小寫字母,使用’_’分隔符分割不同單詞,且使用static關(guān)鍵字限制函數(shù)作用域。

說明:函數(shù)具有內(nèi)部鏈接屬性的含義是函數(shù)只能在模塊或文件內(nèi)部調(diào)用,對文件或模塊外來說是不可見的。如果一個函數(shù)僅在模塊內(nèi)部或者文件內(nèi)部使用,需要限制函數(shù)使用范圍,使用static修飾符修飾函數(shù),使其只具有內(nèi)部鏈接屬性。

在源文件中聲明一遍具有內(nèi)部鏈接的函數(shù)同樣具有促使編譯器檢查函數(shù)聲明和調(diào)用的一致性。

實例:

staticcharget_key(void);

規(guī)則1.4-4(強制):函數(shù)參數(shù)使用小寫字母,各單詞之間使用“_”分割,盡量保持參數(shù)順序從左到右為:輸入、修改、輸出。

說明:函數(shù)參數(shù)順序為需輸入?yún)?shù)值(這個值一般不修改,若不需要修改使用const關(guān)鍵字修飾),需修改的參數(shù)(這個參數(shù)輸入后用于提供數(shù)據(jù),函數(shù)內(nèi)部可以修改此參數(shù)),輸出參數(shù)(這個參數(shù)是函數(shù)輸出值)。

1.5 常量的命名規(guī)則

規(guī)則1.5-1(強制):常量(#define定義的常量、枚舉、const定義的常量)的定義使用全大寫字母,單詞之間加 ’_’分割的命名方式。

實例:

#definePI_ROUNDED3.14 constdoublePI_ROUNDED=3.14; enumweekday{SUN,MON,TUE,WED,THU,FRI,SAT};

規(guī)則1.5-2(建議):常數(shù)宏定義時,十六進制數(shù)的表示方法為0xFF。

說明:前面0x中的x小寫,數(shù)據(jù)中的”A-F”大寫。

1.6 新定義的類型命名規(guī)范

規(guī)則1.6-1(強制):新定義類型名的命名應(yīng)該明確抽象對象的含義,新類型名使用大寫字母,單詞之間加’_’分割,新類型指針在類型名前增加前綴”P_”。

成員變量標示符前加類型名稱前綴,首字母大寫用于區(qū)分各個單詞。

實例:

typedefstruct_STUDENT { StudentName; StudentAge; ...... }STUDENT,*P_STUDENT; /*STUDENT為新類型名稱,P_STUDENT為新類型指針名*/

2 外觀布局

2.1 排版與格式

2.1.1 頭文件排版

規(guī)則2.1.1-1(強制):頭文件排版內(nèi)容依次為包含的頭文件、宏定義、類型定義、聲明變量、聲明函數(shù)。且各個種類的內(nèi)容間空三行。

說明:頭文件是模塊對外的公用接口。在頭文件中定義的宏,可以被其他模塊引用。Project中不建議使用全部變量,若使用則需在頭文件里對外聲明。模塊對外的函數(shù)接口在模塊頭文件里聲明。

2.1.2 源文件排版

規(guī)則2.1.2-1(強制):源文件排版內(nèi)容依次為包含的頭文件、宏定義、具有外部鏈接屬性的全局變量定義、模塊內(nèi)部使用的static變量、具有內(nèi)部鏈接的函數(shù)聲明、函數(shù)實現(xiàn)代碼。且各個種類的內(nèi)容間空三行。

說明:模塊內(nèi)部定義的宏,只能在該模塊內(nèi)部使用。只在模塊內(nèi)部使用的函數(shù),需在源碼文件中聲明,用于促使編譯器檢查函數(shù)聲明和調(diào)用的一致性。

規(guī)則2.1.2-2(強制):程序塊采用縮進風格編寫,每級縮進4個空格。

說明:當前主流IDE都支持Tab縮進,使用Tab縮進需要打開和設(shè)置相關(guān)選項。宏定義、編譯開關(guān)、條件預處理語句可以頂格。

規(guī)則2.1.2-3(強制):if、for、do、while、case、switch、defaul、typedef等語句獨占一行,且這些關(guān)鍵字后需空一格。

說明:執(zhí)行語句必須用縮進風格寫,屬于if、for、do、while、case、switch、default、typedef等的下一個縮進級別。一般寫if、for、do、while等語句都會有成對出現(xiàn)的{}?,if、for、do、while等語句后的執(zhí)行語句建議增加成對的“{}”;如果if/else語句塊中只有一條語句,也需增加“{}”。

實例:

for(i=0;i

規(guī)則2.1.2-4(強制):進行雙目運算、賦值時,操作符之前、之后要加空格;進行非對等操作時,如果是關(guān)系密切的立即操作符(如->),后不應(yīng)加空格。

說明:采用這種方式書寫代碼,主要目的是使代碼更清晰,使關(guān)鍵操作符更突出。

實例:

(1)比較操作符, 賦值操作符"="、 "+=",算術(shù)操作符"+"、"%",邏輯操作符"&&"、"&",位域操作符"<<"、"^"等雙目操作符的前后加空格。

If(a>b) a+=2; b=a^3;

(2)"!"、"~"、"++"、"--"、"&"(地址操作符)等單目操作符前后不加空格。

Search_dowm=!true; a++;

(3)"->"、"."、”[]”前后不加空格。

Weight=G_Car->weight; eye=People.eye; array[8]=8;

規(guī)則2.1.2-5(建議):一行只定義一個變量,一行只書寫一條執(zhí)行語句,多行同類操作時操作符盡量保持對齊。

說明:一行定義一個變量,一行只書寫一條執(zhí)行語句,方便注釋,多行同類操作對齊美觀、整潔。

實例:

events_rdy=OS_FALSE; events_rdy_nbr=0; events_stat=OS_STAT_RDY; pevents=pevents_pend; pevent=*pevents;

規(guī)則2.1.2-6(建議):函數(shù)內(nèi)部局部變量定義和函數(shù)語句之間應(yīng)空三行。

說明:局部變量定義和函數(shù)語句是相對獨立的,而且空三行可以更清晰地表示出這種獨立性。

3 注釋

3.1 注釋原則

原則3.1-1(強制):注釋的內(nèi)容要清楚、明了,含義準確,在代碼的功能、意圖層次上進行注釋。

說明:注釋的目的是讓讀者快速理解代碼的意圖。注釋不是為了名詞解釋(what),而是說明用途(why)。

實例:

如下注釋純屬多余:

++i;//i增加1 if(data_ready)/*如果data_ready為真*/

如下注釋無任何參考價值:

// 時間有限,現(xiàn)在是:04,根本來不及想為什么,也沒人能幫我說清楚

原則3.1-2(強制):注釋應(yīng)分為兩個角度進行,首先是應(yīng)用角度,主要是告訴使用者如何使用接口(即你提供的函數(shù)),其次是實現(xiàn)角度,主要是告訴后期升級、維護的技術(shù)人員實現(xiàn)的原理和細節(jié)。

說明:每一個產(chǎn)品都可以分為三個層次,產(chǎn)品本身是一個層次,這個層次之下的是你使用的更小的組件,這個層次之上的是你為別人提供的服務(wù)。你這個產(chǎn)品的存在的價值就在于把最底層的小部件的使用細節(jié)隱藏,同時給最上層的用戶提供方便、簡潔的

使用接口,滿足需求。

從這個角度來看軟件的注釋,你應(yīng)該時刻想著你寫的注釋是給那一層次的人員看的,如果是用戶,那么你應(yīng)該注重描述如何使用,如果是后期維護者,那么你應(yīng)該注重原理和實現(xiàn)細節(jié)。

原則3.1-3(強制):修改代碼時,應(yīng)維護代碼周邊的注釋,使其代碼和注釋一致,不再使用的注釋應(yīng)刪除。

說明:注釋的目的在于幫助讀者快速理解代碼使用方法或者實現(xiàn)細節(jié),若注釋和代碼不一致會起到相反的作用。建議在修改代碼前應(yīng)該先修改注釋。

規(guī)則3.1-4(建議):代碼段不應(yīng)被“注釋掉”(comment out )。

說明:當源代碼段不需要被編譯時,應(yīng)該使用條件編譯來完成(如帶有注釋的#if或#ifdef 結(jié)構(gòu))。為這種目的使用注釋的開始和結(jié)束標記是危險的,因為C 不支持/**/嵌套的注釋,而且已經(jīng)存在于代碼段中的任何注釋將影響執(zhí)行的結(jié)果。

3.2 文件注釋

規(guī)則3.2-1(強制):文件注釋需放到文件開頭,具體格式見實例。

實例:

stm32f10x_dac.h /** ****************************************************************************** *@filestm32f10x_dac.h *@briefThisfilecontainsallthefunctionsprototypesfortheDACfirmware *library. *@authorMCDApplicationTeam *@versionV3.5.0 *@date11-March-2014 *@parModification:添加函數(shù),支持********
*History *Version:V3.0.1
*Author:***
*Modification:添加函數(shù),支持********
*Version:V3.0.0
*Author:***
*Modification:添加函數(shù),支持********
************************************************************************* *@attention ********************************************************* */

說明:注釋格式可被doxygen工具識別,其中@file、@brief、@author等是doxygen工具識別的關(guān)鍵字,注釋內(nèi)容可以為中文。

3.3 函數(shù)注釋

規(guī)則3.3-1(強制):函數(shù)注釋分為頭文件中函數(shù)原型聲明時的注釋和源文件中函數(shù)實現(xiàn)時的注釋。頭文件中的注釋注重函數(shù)使用方法和注意事項,源文件中的注釋注重函數(shù)實現(xiàn)原理和方法。具體格式見實例。

說明:函數(shù)原型聲明的注釋按照doxygen工具可以識別的格式進行注釋,用于doxygen工具生成頭文件信息以及函數(shù)間的調(diào)用關(guān)系信息。

源代碼實現(xiàn)主要是注釋函數(shù)實現(xiàn)原理及修改記錄,不需按照doxygen工具要求的注釋格式進行注釋。

實例:

頭文件函數(shù)原型聲明注釋:

/** ******************************************************************** *@briefConfiguresthediscontinuousmodefortheselectedADCregular *groupchannel. *@paramADCx:wherexcanbe1,2or3toselecttheADCperipheral. *@paramNumber:specifiesthediscontinuousmoderegularchannel *countvalue.Thisnumbermustbebetween1and8. *@retvalNone *@par Usage: *ADC_DiscModeChannelCountConfig(ADC1,6);
*@parTag: *此函數(shù)不能在中斷里調(diào)用。 ******************************************************************** */ voidADC_DiscModeChannelCountConfig(ADC_TypeDef*ADCx,INT8U_tNumber);

源文件函數(shù)實現(xiàn)注釋:

/* ******************************************************************** *@briefConfiguresthediscontinuousmodefortheselectedADCregular *groupchannel. *@paramADCx:wherexcanbe1,2or3toselecttheADCperipheral. *@paramNumber:specifiesthediscontinuousmoderegularchannel *countvalue.Thisnumbermustbebetween1and8. *@retvalNone *@parModification:修改了********
*History * Modified by:***
*Date:2013-10-10 *Modification:修改了********
******************************************************************** */ voidADC_DiscModeChannelCountConfig(ADC_TypeDef*ADCx,INT8U_tNumber) { 賦值語句*********;/*關(guān)鍵語句的注釋*/ 語句***********;/*關(guān)鍵語句的注釋格式*/ 語句*******;/*實現(xiàn)*****************功能*/ }

3.4 常量及全局變量注釋

規(guī)則3.3-1(強制):常量、全局變量需要注釋,注釋格式見實例。

實例:

/**Descriptionofthemacro*/ #defineXXXX_XXX_XX0 /**Descriptionofglobalvariable*/ INT8UG_xxx=0;

說明:若全局變量在.c文件中定義,又在.h文件中聲明,則在頭文件中使用doxygen

格式注釋,在源碼文件中使用 /* Description of the globalvariable */的形式。

防止doxygen生成兩遍注釋文檔信息。

3.5 局部變量及語句注釋

規(guī)則3.3-1(強制):局部變量,函數(shù)實現(xiàn)關(guān)鍵語句需要注釋,注釋格式見實例。

實例:

*pq->OSQIn++=pmsg;/*Insertmessageintoqueue*/ pq->OSQEntries++;/*Updatethenbrofentriesinthequeue*/ if(pq->OSQIn==pq->OSQEnd) { pq->OSQIn=pq->OSQStart;/*WrapINptrifweareatendofqueue*/ }

說明:局部變量,關(guān)鍵語句需要注釋,從功能和意圖上進行注釋,而不是代碼的重復。多條注釋語句盡量保持對齊,實現(xiàn)美觀,整潔。

參考材料:

1. 《代碼整潔之道》(RobertC.Martin 著 韓磊 譯 人民郵電出版社2010年1月)第四章"注釋”。

2.《Doxygen中文手冊》

4 項目版本號命名規(guī)范

項目版本號管理是項目管理的重要方面,我們根據(jù)項目不同的開發(fā)階段制定了不同的版本號命名規(guī)范。

項目開發(fā)過程一般分為前期開發(fā)測試階段、發(fā)布階段、維護階段這三個主要階段,我們分別制定了命名規(guī)范。

4.1 開發(fā)、測試階段版本號命名

規(guī)則4.1-1(強制):處于開發(fā)、調(diào)試階段的項目,版本號使用“V0.yz”的形式。

說明:處于新開發(fā)、調(diào)試階段的項目,版本號使用“V0.yz” 的形式,比如新開發(fā)的項目正處在開發(fā)、調(diào)試階段,這時可以使用“ V0.10 ”這樣的版本號。

你認為完成了新的功能模塊或整體架構(gòu)做了很大的修改,可以根據(jù)情況增加 Y 或者 Z的值。比如,你開發(fā)階段在“ V0.10 ”基礎(chǔ)上新增加了一個功能模塊你可以將版本號改為“V0.11”,做了比較大的修改,你可以將版本號定為“V0.20”。

4.2 正式發(fā)布階段版本號命名

規(guī)則4.2-1(強制):處于正式發(fā)布階段的項目,版本號使用“Vx.y”的形式。

說明:處于正式發(fā)布的項目版本號使用“Vx.y”的形式。比如,你發(fā)布了一個正式面向市場的項目,你可以使用“V1.0”作為正式的版本號。在“V1.0”基礎(chǔ)上增加功能的正式版本,你可以使用“V1.1”作為下一次正式版本的版本號,在“V1.0”基礎(chǔ)上修正了大的BUG或者做了很大的改動,你可以使用“V2.0”作為下一次正式版本號。

4.3 維護階段版本號命名

規(guī)則4.3-1(強制):處于維護階段的項目,版本號使用“Vx.yz”的形式。

說明:處于維護階段的項目版本號使用“Vx.yz”的形式。比如在"V1.1"的基礎(chǔ)上修改了一個功能實現(xiàn)算法以實現(xiàn)高效率,則可以使用"V1.11" 來表示這是在正式發(fā)布版本“V1.1”的基礎(chǔ)上進行的一次修正,再次修正可以使用“V1.12”。

5 嵌入式軟件安全性相關(guān)規(guī)范

5.1頭文件

原則5.1-1(強制):頭文件用于聲明模塊對外接口,包括具有外部鏈接的函數(shù)原型聲明、全局變量聲明、定義的類型聲明等。

說明:頭文件是模塊(Module)或單元(Unit)的對外接口。頭文件中應(yīng)放置對外部的聲明,如對外提供的函數(shù)聲明、宏定義、類型定義等。內(nèi)部使用的函數(shù)聲明不應(yīng)放在頭文件中。內(nèi)部使用的宏、枚舉、結(jié)構(gòu)定義不應(yīng)放入頭文件中。變量定義不應(yīng)放在頭文件中,應(yīng)放在.c文件中。

變量的聲明盡量不要放在頭文件中,亦即盡量不要使用全局變量作為接口。變量是模塊或單元的內(nèi)部實現(xiàn)細節(jié),不應(yīng)通過在頭文件中聲明的方式直接暴露給外部,應(yīng)通過函數(shù)接口的方式進行對外暴露。即使必須使用全局變量,也只應(yīng)當在.c中定義全局變量,在.h中僅聲明變量為全局的。

參考材料:《C語言接口與實現(xiàn)》(David R. Hanson著 傅蓉 周鵬 張昆琪權(quán)威 譯 機械工業(yè)出版社 2004年1月)(英文版:"C Interfaces and Implementations")

規(guī)則5.1-2(強制):只能通過包含頭文件的方式使用其他.c提供的接口,禁止在.c中通過extern的方式使用外部函數(shù)接口、變量。

說明:若a.c使用了b.c定義的foo()函數(shù) ,則應(yīng)當在b.h中聲明externintfoo(int input);并在a.c中通過#include來使用foo。禁止通過在a.c中寫externintfoo(int input)來使用foo,后面這種寫法容易在foo改變時可能導致聲明和定義不一致。

規(guī)則5.1-3(強制):使用#define定義保護符,防止頭文件重復包含。

說明:多次包含一個頭文件可以通過認真的設(shè)計來避免。如果不能做到這一點,就需要采取阻止頭文件內(nèi)容被包含多于一次的機制。通常的手段是為每個文件配置一個宏,當頭文件第一次被包含時就定義這個宏,并在頭文件被再次包含時使用它以排除文件內(nèi)容。所有頭文件都應(yīng)當使用#define 防止頭文件被多重包含,命名格式FILENAME_H_,其中FILENAME 為頭文件的名稱。

實例:

若文件名為:stm32f10x_adc.h。

#ifndefSTM32F10x_DAC_H_ #defineSTM32F10x_DAC_H_ ………… 受保護的代碼 #endif

5.2 預處理命令

規(guī)則5.2-1(強制):C的宏只能擴展為用大括號括起來的初始化、常量、小括號括起來的表達式、類型限定符、存儲類標識符或do-while-zero 結(jié)構(gòu)。

說明:這些是宏當中所有可允許使用的形式。存儲類標識符和類型限定符包括諸如extern、static和const這樣的關(guān)鍵字。使用任何其他形式的#define 都可能導致非預期的行為,或者是非常難懂的代碼。

特別的,宏不能用于定義語句或部分語句,除了do-while 結(jié)構(gòu)。宏也不能重定義語言的語法。

宏的替換列表中的所有括號,不管哪種形式的 ()、{} 、[] 都應(yīng)該成對出現(xiàn)。do-while-zero 結(jié)構(gòu)(見下面實例)是在宏語句體中唯一可接受的具有完整語句的形式。do-while-zero 結(jié)構(gòu)用于封裝語句序列并確保其是正確的。

注意:在宏語句體的末尾必須省略分號。

實例:

以下是合理的宏定義:

#definePI3.14159F/*Constant*/ #defineXSTAL10000000/*Constant*/ #defineCLOCK(XSTAL/16)/*Constantexpression*/ #definePLUS2(X)((X)+2)/*Macroexpandingtoexpression*/ #defineSTORextern/*storageclassspecifier*/ #defineINIT(value){(value),0,0}/*bracedinitialiser*/ #defineREAD_TIME_32() do{ DISABLE_INTERRUPTS(); time_now=(INT32U)TIMER_HI<

以下是不合理的宏定義:

#defineunsignedintlong/*usetypedefinstead*/ #defineSTARTIFif(/*unbalanced()andlanguageredefinition*/

規(guī)則5.2-2(強制):在定義函數(shù)宏時,每個參數(shù)實例都應(yīng)該以小括號括起來。

實例:

一個abs 函數(shù)可以定義成:

#defineabs(x)(((x)>=0)?(x):-(x))

不能定義成:

#defineabs(x)(((x)>=0)?x:-x)

如果不堅持本規(guī)則,那么當預處理器替代宏進入代碼時,操作符優(yōu)先順序?qū)⒉粫o出要求的結(jié)果。

考慮前面第二個不正確的定義被替代時會發(fā)生什么:

z=abs(a–b);

將給出如下結(jié)果:

z=((a–b>=0)?a–b:-a–b);

子表達式 – a - b 相當于 (-a)-b ,而不是希望的 –(a-b) 。

把所有參數(shù)都括進小括號中就可以避免這樣的問題。

規(guī)則5.2-3(建議):使用宏時,不允許參數(shù)數(shù)值發(fā)生變化。

實例:

如下用法可能導致錯誤。

#defineSQUARE(a)((a)*(a)) inta=5; intb; b = SQUARE(a++);/*結(jié)果:a = 7,即執(zhí)行了兩次增。

正確的用法是:

b=SQUARE(a); a++;/*結(jié)果:a = 6,即只執(zhí)行了一次增*/

同樣建議在調(diào)用函數(shù)時,參數(shù)也不要變化,如果某次軟件升級將其中一個接口由函數(shù)實現(xiàn)轉(zhuǎn)換成宏,那參數(shù)數(shù)值發(fā)生變化的調(diào)用將產(chǎn)生非預期效果。

規(guī)則5.2-4(建議):除非必要,應(yīng)盡可能使用函數(shù)代替宏。

說明:宏能提供比函數(shù)優(yōu)越的速度,但是沒有參數(shù)檢查機制,不當?shù)氖褂每赡墚a(chǎn)生非預期后果。

5.3 類型及類型轉(zhuǎn)換

規(guī)則5.3-1(強制):應(yīng)該使用標明了大小和符號的typedef代替基本數(shù)據(jù)類型。不應(yīng)使用基本數(shù)值類型char、int、short、long、float和double,而應(yīng)使用typedef進行類型的定義。

說明:為了程序的跨平臺移植性,我們使用typedef定義指明了大小和符號的數(shù)據(jù)類型。

實例:

此實例是根據(jù)keil for ARM的數(shù)據(jù)類型大小進行的定義。

No. 基本數(shù)據(jù)類型 Typedef定義
1 typedef unsigned char BOOLEAN
2 typedef unsigned char INT8U
3 typedef signed char INT8S
4 typedef unsigned short INT16U
5 typedef signed short INT16S
6 typedef unsigned int INT32U
7 typedef signed int INT32S
8 typedef float FP32
9 typedef double FP64

應(yīng)根據(jù)硬件平臺和編譯器的信息對基本類型進行定義。

規(guī)則5.3-2(建議):浮點應(yīng)用應(yīng)該適應(yīng)于已定義的浮點標準。

說明:浮點運算會帶來許多問題,一些問題(而不是全部)可以通過適應(yīng)已定義的標準來克服。其中一個合適的標準是 ANSI/IEEE Std 754 [1] 。

5.3.1 顯式數(shù)據(jù)類型轉(zhuǎn)換

C 語言給程序員提供了相當大的自由度并允許不同數(shù)值類型可以自動轉(zhuǎn)換。由于某些功能性的原因可以引入顯式的強制轉(zhuǎn)換,例如:

1.用以改變類型使得后續(xù)的數(shù)值操作可以進行

2.用以截取數(shù)值

3.出于清晰的角度,用以執(zhí)行顯式的類型轉(zhuǎn)換

為了代碼清晰的目的而插入的強制轉(zhuǎn)換通常是有用的,但如果過多使用就會導致程序的可讀性下降。正如下面所描述的,一些隱式轉(zhuǎn)換是可以安全地忽略的,而另一些則不能。

規(guī)則5.3.1-1(強制):強制轉(zhuǎn)換只能向表示范圍更窄的方向轉(zhuǎn)換,且與被轉(zhuǎn)換對象的類

型具有相同的符號。浮點類型值只能強制轉(zhuǎn)換到更窄的浮點類型。

說明:這條規(guī)則主要是要求需要強制轉(zhuǎn)換時,須明確被轉(zhuǎn)換對象的表示范圍及轉(zhuǎn)換后的表示范圍。轉(zhuǎn)換時盡量保持符號一致,不同符號對象之間不應(yīng)出現(xiàn)強制轉(zhuǎn)換。向更寬數(shù)據(jù)范圍轉(zhuǎn)換并不能提高數(shù)據(jù)精確度,并沒有實際意義。在程序中盡量規(guī)劃好變量范圍,盡量少使用強制轉(zhuǎn)換。

規(guī)則5.3.1-2(強制):如果位運算符 ~ 和 <

說明:當這些操作符(~ 和<<)用在 small integer 類型(unsigned char 或unsigned short )時,運算之前要先進行整數(shù)提升,結(jié)果可能包含并非預期的高端數(shù)據(jù)位。

例如:

INT8Uport=0x5aU; NT8Uresult_8; INT16Uresult_16; INT16Umode; result_8=(~port)>>4;/*不合規(guī)范*/

~port的值在16位機器上是 0xffa5 ,而在 32 位機器上是 0xffffffa5 。在每種情況下,result的值是0xfa ,然而期望值可能是0x0a 。

這樣的危險可以通過如下所示的強制轉(zhuǎn)換來避免:

result_8=((INT8U)(~port))>>4;/*符合規(guī)范*/ result_16=((INT16U)(~(INT16U)port))>>4;/*符合規(guī)范*/

當<<操作符用在 smallinteger 類型時會遇到類似的問題,高端數(shù)據(jù)位被保留下來。

例如:

result_16=((port<>6;/*不符合規(guī)范*/ result_16 的值將依賴于 int 實現(xiàn)的大小。附加的強制轉(zhuǎn)換可以避免任何模糊性。 result_16=((INT16U)((INT16U)port<>6;/*符合規(guī)范*/

5.3.2 隱式類型轉(zhuǎn)換

規(guī)則5.3.2-1(強制):以下類型之間不應(yīng)該存在隱式類型轉(zhuǎn)換。

1)有符號和無符號之間沒有隱式轉(zhuǎn)換

2)整型和浮點類型之間沒有隱式轉(zhuǎn)換

3)沒有從寬類型向窄類型的隱式轉(zhuǎn)換

4)函數(shù)參數(shù)沒有隱式轉(zhuǎn)換

5)函數(shù)的返回表達式?jīng)]有隱式轉(zhuǎn)換

6)復雜表達式?jīng)]有隱式轉(zhuǎn)換

5.3.3 整數(shù)后綴

規(guī)則5.3.3-1(強制):后綴“U”應(yīng)該用在所有unsigned 類型的常量上。

整型常量的類型是混淆的潛在來源,因為它依賴于許多因素的復雜組合,包括:

1)常數(shù)的量級

2)整數(shù)類型實現(xiàn)的大小

3)任何后綴的存在

4)數(shù)值表達的進制(即十進制、八進制或十六進制)

例如,整型常量“40000”在32位環(huán)境中是 int 類型,而在 16位環(huán)境中則是long 類型。值0x8000 在16位環(huán)境中是 unsigned int 類型,而在 32 位環(huán)境中則是(signed )int 類型。

注意:

1)任何帶有“U”后綴的值是unsigned 類型

2)一個不帶后綴的小于231的十進制值是signed 類型

但是:

1)不帶后綴的大于或等于215的十六進制數(shù)可能是 signed 或unsigned 類型

2)不帶后綴的大于或等于231的十進制數(shù)可能是 signed 或unsigned 類型

常量的符號應(yīng)該明確。符號的一致性是構(gòu)建良好形式的表達式的重要原則。如果一個常數(shù)是unsigned 類型,為其加上“U”后綴將有助于避免混淆。當用在較大數(shù)值上時,后綴也許是多余的(在某種意義上它不會影響常量的類型);然而后綴的存在對代碼的清晰性是種有價值的幫助。

5.3.4 指針類型轉(zhuǎn)換

指針類型可以歸為如下幾類:

1)對象指針

2)函數(shù)指針

3)void 指針

4)空(null )指針常量(即由數(shù)值 0 強制轉(zhuǎn)換為 void*類型)

涉及指針類型的轉(zhuǎn)換需要明確的強制,除非在以下時刻:

1)轉(zhuǎn)換發(fā)生在對象指針和void 指針之間,而且目標類型承載了源類型的所有類型標識符。

2)當空指針常量(void*)被賦值給任何類型的指針或與其做等值比較時,空指針常量被自動轉(zhuǎn)化為特定的指針類型。

C 當中只定義了一些特定的指針類型轉(zhuǎn)換,而一些轉(zhuǎn)換的行為是實現(xiàn)定義的。

規(guī)則5.3.9-1(強制):轉(zhuǎn)換不能發(fā)生在函數(shù)指針和其他除了整型之外的任何類型指針之間。

[Undefined]

說明:

函數(shù)指針到不同類型指針的轉(zhuǎn)換會導致未定義的行為。這意味著一個函數(shù)指

針不能轉(zhuǎn)換成指向不同類型函數(shù)的指針。

規(guī)則5.3.9-2(強制):對象指針和其他除整型之外的任何類型指針之間、對象指針和其他類型對象的指針之間、對象指針和void指針之間不能進行轉(zhuǎn)換。

[Undefined]

規(guī)則5.3.9-3(強制):不應(yīng)在某類型對象指針和其他不同類型對象指針之間進行強制轉(zhuǎn)換。

說明:如果新的指針類型需要更嚴格的分配時這樣的轉(zhuǎn)換可能是無效的。

實例:

INT8U*p1; INT32U*p2; p2=(INT32U*)p1;/*不符規(guī)范*/

5.4 初始化、聲明與定義

規(guī)則5.4-1(強制):所有自動變量在使用前都應(yīng)被賦值。

[Undefined]

說明:注意,根據(jù)ISO C[2] 標準,具有靜態(tài)存儲期的變量缺省地被自動賦予零值,除非經(jīng)過了顯式的初始化。實際中,一些嵌入式環(huán)境沒有實現(xiàn)這樣的缺省行為。

靜態(tài)存儲期是所有以static存儲類形式聲明的變量或具有外部鏈接的變量的共同屬性,自動存儲期變量通常不是自動初始化的。

規(guī)則5.4-2(強制):應(yīng)該使用大括號以指示和匹配數(shù)組和結(jié)構(gòu)的非零初始化構(gòu)造。

[Undefined]

說明:

ISO C[2]要求數(shù)組、結(jié)構(gòu)和聯(lián)合的初始化列表要以一對大括號括起來(盡管不這樣做的行為是未定義的)。本規(guī)則更進一步地要求,使用附加的大括號來指示嵌套的結(jié)構(gòu)。它迫使程序員顯式地考慮和描述復雜數(shù)據(jù)類型元素(比如,多維數(shù)組)的初始化次序。

例如,下面的例子是二維數(shù)組初始化的有效(在ISO C [2]中)形式,但第一個與本規(guī)則相違背:

在結(jié)構(gòu)中以及在結(jié)構(gòu)、數(shù)組和其他類型的嵌套組合中,規(guī)則類似。

還要注意的是,數(shù)組或結(jié)構(gòu)的元素可以通過只初始化其首元素的方式初始化(為 0 或

NULL)。如果選擇了這樣的初始化方法,那么首元素應(yīng)該被初始化為0(或NULL),此時不需要使用嵌套的大括號。

實例:

INT16Utest[3][2]={1,2,3,4,5,6};/*不符合此規(guī)則*/ INT16Utest[3][2]={{1,2},{3,4},{5,6}};/*符合此規(guī)則*/

規(guī)則5.4-3(強制):在枚舉列表中,“= ”不能顯式用于除首元素之外的元素上,除非所有的元素都是顯式初始化的。

說明:

如果枚舉列表的成員沒有顯式地初始化,那么C 將為其分配一個從0 開始的整數(shù)序列,首元素為0 ,后續(xù)元素依次加 1 。

如上規(guī)則允許的,首元素的顯式初始化迫使整數(shù)的分配從這個給定的值開始。當采用這種方法時,重要的是確保所用初始化值一定要足夠小,這樣列表中的后續(xù)值就不會超出該枚舉常量所用的int 存儲量。

列表中所有項目的顯式初始化也是允許的,它防止了易產(chǎn)生錯誤的自動與手動分配的混合。然而,程序員就該擔負職責以保證所有值都處在要求的范圍內(nèi)以及值不是被無意復制的。

實例:

enum colour { red = 3, blue, green, yellow = 5 }; /* 不符合此規(guī)則 */

enum colour { red = 3, blue = 4, green = 5, yellow= 5 }; /* 符合此規(guī)則 */

雖然green和yellow的值都是5,但這符合規(guī)則。

enum colour { red = 1, blue, green, yellow }; /* 符合此規(guī)則 */

規(guī)則5.4-4(強制):函數(shù)應(yīng)當具有原型聲明,且原型在函數(shù)的定義和調(diào)用范圍內(nèi)都是可見的。

[Undefined]

說明:原型的使用使得編譯器能夠檢查函數(shù)定義和調(diào)用的完整性。如果沒有原型,就不會迫使編譯器檢查出函數(shù)調(diào)用當中的一定錯誤(比如,函數(shù)體具有不同的參數(shù)數(shù)目,調(diào)用和定義之間參數(shù)類型的不匹配)。

事實證明,函數(shù)接口是相當多問題的肇因,因此本規(guī)則是相當重要的。對外部函數(shù)來說,我們建議采用如下方法,在頭文件中聲明函數(shù)(亦即給出其原型),并在所有需要該函數(shù)原型的代碼文件中包含這個頭文件,在實現(xiàn)函數(shù)功能的.c文件中也包含具有原型聲明的頭文件。為具有內(nèi)部鏈接的函數(shù)給出其原型也是良好的編程實踐。

規(guī)則5.4-5(強制):定義或聲明對象、函數(shù)時都應(yīng)該顯示指明其類型。

規(guī)則5.4-6(強制):函數(shù)的每個參數(shù)類型在聲明和定義中必須是等同的,函數(shù)的返回類型也該是等同的。

[Undefined]

規(guī)則5.4-6(強制):函數(shù)應(yīng)該聲明為具有文件作用域。

[Undefined]

說明:在塊作用域中聲明函數(shù)會引起混淆并可能導致未定義的行為。

規(guī)則5.4-7(強制):在文件范圍內(nèi)聲明和定義的所有對象或函數(shù)應(yīng)該具有內(nèi)部鏈接,除非是在需要外部鏈接的情況下,具有內(nèi)部鏈接屬性的對象或函數(shù)應(yīng)該使用static關(guān)鍵字修飾。

說明:如果一個變量只是被同一文件中的函數(shù)所使用,那么就用static。類似地,如果一個函數(shù)只是在同一文件中的其他地方調(diào)用,那么就用 static。

使用 static存儲類標識符將確保標識符只是在聲明它的文件中是可見的,并且避免了和其他文件或庫中的相同標識符發(fā)生混淆的可能性。具有外部鏈接屬性的對象或函數(shù)在相應(yīng)模塊的頭文件中聲明,在需要使用這些接口的模塊中包含此頭文件。

規(guī)則5.4-8(強制):當一個數(shù)組聲明為具有外部鏈接,它的大小應(yīng)該顯式聲明或者通過初始化進行隱式定義。

[Undefined]

實例:

INT8Uarray[10];/*符合規(guī)范*/ externINT8Uarray[];/*不符合規(guī)范*/ INT8Uarray[]={0,10,15};/*符合規(guī)范*/

盡管可以在數(shù)組聲明不完善時訪問其元素,然而仍然是在數(shù)組的大小可以顯式確定的情況下,這樣做才會更為安全。

5.5 控制語句和表達式

規(guī)則5.5-1(建議):不要過分依賴C 表達式中的運算符優(yōu)先規(guī)則。

說明:括號的使用除了可以覆蓋缺省的運算符優(yōu)先級以外,還可以用來強調(diào)所使用的運算符。使用相當復雜的C 運算符優(yōu)先級規(guī)則很容易引起錯誤,那么這種方法就可以幫助避免這樣的錯誤,并且可以使得代碼更為清晰可讀。

然而,過多的括號會分散代碼使其降低了可讀性。因此,請合理使用括號來提高程序清晰度和可讀性。

規(guī)則5.5-1(強制):不能在具有副作用的表達式中使用sizeof 運算符。

說明:當一個表達式使用了sizeof運算符,并期望計算表達式的值時,表達式是不會被計算的。sizeof只對表達式的類型有用。

實例:

INT32S i;

INT32S j;

j = sizeof (i = 1234);

/*j的值是i類型的大小,但i的值并沒有賦值成1234 */

規(guī)則5.5-2(強制):邏輯運算符 && 或 || 的右手操作數(shù)不能包含副作用。

說明:C語言中存在表達式的某些部分不會被計算到,這取決于表達式中的其他部分。邏輯操作符&&或||在進行邏輯判斷時,若僅判別左操作數(shù)就能確定true or false的情況下,邏輯操作符的右操數(shù)將被忽略。

實例:

if ( high && ( x == i++ ) ) /* 不符合規(guī)則 */

若high為false,則整個表達式的布爾值也即為false,不用再去執(zhí)行和判斷右操作數(shù)。

規(guī)則5.5-3(建議):邏輯運算符(&&、| | 和 ! )的操作數(shù)應(yīng)該是有效的布爾數(shù)。有效布爾類型的表達式不能用做非邏輯運算符(&&、| | 和 ! )的操作數(shù)。

說明:有效布爾類型是表示真、假的一種數(shù)據(jù)類型,產(chǎn)生布爾類型的可以是比較,邏輯運算,但布爾類型數(shù)據(jù)只能進行邏輯運算。

規(guī)則5.5-4(強制):位運算符不能用于基本類型(underlying type )是有符號的操作數(shù)上。

[Implementation-defined]

說明:位運算(~ 、<<、>>、&、^ 和 | )對有符號整數(shù)通常是無意義的。比如,如果右移運算把符號位移動到數(shù)據(jù)位上或者左移運算把數(shù)據(jù)位移動到符號位上,就會產(chǎn)生問題。

規(guī)則5.5-6(建議):在一個表達式中,自增(++)和自減(- - )運算符不應(yīng)同其他運算符混合在一起。

說明:不建議使用同其他算術(shù)運算符混合在一起的自增和自減運算符是因為

1)它顯著削弱了代碼的可讀性;

2)在不同的變異環(huán)境下,會執(zhí)行不同的運算次序,產(chǎn)生不同結(jié)果。

實例:

u8a = ++u8b +u8c--; /* 不符合規(guī)范 */

下面的序列更為清晰和安全:

++u8b; u8a=u8b+u8c; u8c--;

規(guī)則5.5-7(強制):浮點表達式不能做像‘>’ ‘<’ ‘==’ ‘!=’等 關(guān)系運算。

說明:float、double類型的數(shù)據(jù)都有一定的精確度限制,使用不同浮點數(shù)表示規(guī)范或者不同硬件平臺可能導致關(guān)系運算的結(jié)果不一致。

規(guī)則5.5-8(強制):for語句的三個表達式應(yīng)該只關(guān)注循環(huán)控制,for循環(huán)中用于計數(shù)的變量不應(yīng)在循環(huán)體中修改。

說明:for 語句的三個表達式都給出時它們應(yīng)該只用于如下目的:

第一個表達式初始化循環(huán)計數(shù)器;

第二個表達式包含對循環(huán)計數(shù)器和其他可選的循環(huán)控制變量的測試;

第三個表達式循環(huán)計數(shù)器的遞增或遞減。

規(guī)則5.5-9(強制):組成switch、while、do...while 或for 結(jié)構(gòu)體的語句應(yīng)該是復合語句。即使該復合語句只包含一條語句也要擴在{}里。

實例:

for(i=0;i

規(guī)則5.5-10(強制):if /else應(yīng)該成對出現(xiàn)。所有的if ... else if 結(jié)構(gòu)應(yīng)該由else 子句結(jié)束。

規(guī)則5.5-11(強制):switch 語句中如果case 分支的內(nèi)容不為空,那么必須以break 作為結(jié)束,最后分支應(yīng)該是default分支。

5.6 函數(shù)

原則5.6-1(強制):編寫整潔函數(shù),同時把代碼有效組織起來。

說明:代碼簡單直接、不隱藏設(shè)計者的意圖、用干凈利落的抽象和直截了當?shù)目刂普Z句將函數(shù)有機組織起來。代碼的有效組織包括:邏輯層組織和物理層組織兩個方面。邏輯層,主要是把不同功能的函數(shù)通過某種聯(lián)系組織起來,主要關(guān)注模塊間的接口,也就是模塊的架構(gòu)。

物理層,無論使用什么樣的目錄或者名字空間等,需要把函數(shù)用一種標準的方法組織起來。例如:設(shè)計良好的目錄結(jié)構(gòu)、函數(shù)名字、文件組織等,這樣可以方便查找。

規(guī)則5.6-2(強制):一定要顯示聲明函數(shù)的返回值類型,及所帶的參數(shù)。如果沒有要聲明為void。

說明:C語言中不加類型說明的函數(shù),一律自動按整型處理。

規(guī)則5.6-3(建議):不建議使用遞歸函數(shù)調(diào)用。

說明:有些算法使用分而治之的遞歸思想,但在嵌入式中棧空間有限,遞歸本身承載著可用堆棧空間過度的危險,這能導致嚴重的錯誤。除非遞歸經(jīng)過了非常嚴格的控制,否則不可能在執(zhí)行之前確定什么是最壞情況(worst-case)的堆棧使用。

5.7 指針與數(shù)組

規(guī)則5.7-1(強制):除了指向同一數(shù)組的指針外,不能用指針進行數(shù)學運算,不能進行關(guān)系運算。

說明:這樣做的目的一是使代碼清晰易讀,另外避免訪問無效的內(nèi)存地址。

規(guī)則5.7-2(強制):指針在使用前一定要賦值,避免產(chǎn)生野指針。

規(guī)則5.7-3(強制):不要返回局部變量的地址。

說明:

局部變量是在棧中分配的,函數(shù)返回后占用的內(nèi)存會釋放,繼續(xù)使用這樣的內(nèi)存是危險的。因此,應(yīng)該避免出現(xiàn)這樣的危險。

實例:

INT8U*foobar(void) { INT8Ulocal_auto; return(&local_auto);/*不符合規(guī)范*/ }

5.8 結(jié)構(gòu)與聯(lián)合

原則5.8-1(強制):結(jié)構(gòu)功能單一,不要設(shè)計面面俱到的數(shù)據(jù)結(jié)構(gòu)。

說明:相關(guān)的一組信息才是構(gòu)成一個結(jié)構(gòu)體的基礎(chǔ),結(jié)構(gòu)的定義應(yīng)該可以明確的描述一個對象,而不是一組相關(guān)性不強的數(shù)據(jù)的集合。設(shè)計結(jié)構(gòu)時應(yīng)力爭使結(jié)構(gòu)代表一種現(xiàn)實事務(wù)的抽象,而不是同時代表多種。

結(jié)構(gòu)中的各元素應(yīng)代表同一事務(wù)的不同側(cè)面,而不應(yīng)把描述沒有關(guān)系或關(guān)系很弱的不同事務(wù)的元素放到同一結(jié)構(gòu)中。

5.9 標準庫

規(guī)則5.9-1(強制):標準庫中保留的標識符、宏和函數(shù)不能被定義、重定義或取消定義。

[Undefined]

說明:通常 #undef 一個定義在標準庫中的宏是件壞事。同樣不好的是,#define 一個宏名字,而該名字是C 的保留標識符或者標準庫中做為宏、對象或函數(shù)名字的C 關(guān)鍵字。

例如,存在一些特殊的保留字和函數(shù)名字,它們的作用為人所熟知,如果對它們重新定義或取消定義就會產(chǎn)生一些未定義的行為。這些名字包括defined、__LINE__、__FILE__、__DATE__ 、__TIME__、__STDC__、errno和assert。

規(guī)則5.9-2(強制):傳遞給庫函數(shù)的值必須檢查其有效性。

說明:

C 標準庫中的許多函數(shù)根據(jù)ISO [2] 標準 并不需要檢查傳遞給它們的參數(shù)的有效性。即使標準要求這樣,或者編譯器的編寫者聲明要這么做,也不能保證會做出充分的檢查。因此,程序員應(yīng)該為所有帶有嚴格輸入域的庫函數(shù)(標準庫、第三方庫及自己定義的庫)提供適當?shù)妮斎胫禉z查機制。

具有嚴格輸入域并需要檢查的函數(shù)例子為:

math.h 中的許多數(shù)學函數(shù),比如:

負數(shù)不能傳遞給sqrt 或log函數(shù);

fmod 函數(shù)的第二個參數(shù)不能為零

toupper 和tolower:當傳遞給toupper函數(shù)的參數(shù)不是小寫字符時,某些實現(xiàn)能產(chǎn)生并非預期的結(jié)果(tolower 函數(shù)情況類似)

如果為ctype.h 中的字符測試函數(shù)傳遞無效的值時會給出未定義的行為

應(yīng)用于大多數(shù)負整數(shù)的abs 函數(shù)給出未定義的行為 在math.h 中,盡管大多數(shù)數(shù)學庫函數(shù)定義了它們允許的輸入域,但在域發(fā)生錯誤時它們的返回值仍可能隨編譯器的不同而不同。因此,對這些函數(shù)來說,預先檢查其輸入值的有效性就變得至關(guān)重要。

程序員在使用函數(shù)時,應(yīng)該識別應(yīng)用于這些函數(shù)之上的任何的域限制(這些限制可能

會也可能不會在文檔中說明),并且要提供適當?shù)臋z查以確認這些輸入值位于各自域

中。當然,在需要時,這些值還可以更進一步加以限制。

有許多方法可以滿足本規(guī)則的要求,包括:

1.調(diào)用函數(shù)前檢查輸入值

2. 設(shè)計深入函數(shù)內(nèi)部的檢查手段。這種方法尤其適應(yīng)于實驗室內(nèi)開發(fā)的庫,縱然它也可以用于買進的第三方庫(如果第三方庫的供應(yīng)商聲明他們已內(nèi)置了檢查的話)。

3. 產(chǎn)生函數(shù)的“封裝”(wrapped)版本,在該版本中首先檢查輸入,然后調(diào)用原始的函數(shù)。

4. 靜態(tài)地聲明輸入?yún)?shù)永遠不會采取無效的值。

注意,在檢查函數(shù)的浮點參數(shù)時(浮點參數(shù)在零點上為奇點),適當?shù)淖龇ㄊ菆?zhí)行其是否為零的檢查。然而如果當參數(shù)趨近于零時,函數(shù)值的量級趨近無窮的話,仍然有必要檢查其在零點(或其他任何奇點)上的容限,這樣可以避免溢出的發(fā)生。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 嵌入式
    +關(guān)注

    關(guān)注

    5087

    文章

    19148

    瀏覽量

    306156
  • C語言
    +關(guān)注

    關(guān)注

    180

    文章

    7608

    瀏覽量

    137135
  • 編譯器
    +關(guān)注

    關(guān)注

    1

    文章

    1636

    瀏覽量

    49173

原文標題:嵌入式C語言的自我修養(yǎng):這樣編出來的代碼簡直行云流水!

文章出處:【微信號:wujianying_danpianji,微信公眾號:單片機精講吳鑒鷹】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    新手怎么學嵌入式?

    的運行機制。例如,了解數(shù)據(jù)結(jié)構(gòu)中的鏈表、棧和隊列,對于在嵌入式編程中管理數(shù)據(jù)非常有幫助。 2. 選擇合適的編程語言 嵌入式開發(fā)中常用的編程語言
    發(fā)表于 12-12 10:51

    嵌入式學習建議

    原理的嵌入式操作系統(tǒng)進行學習。不要一開始就學習幾種操作系統(tǒng),理解了基本原理,實踐中確有實際需要再學習也不遲。人總是要不斷學習的。 ⑨關(guān)于匯編語言C語言的取舍。隨著:MCU對
    發(fā)表于 10-22 11:41

    一種常用嵌入式開發(fā)代碼

    使用開源協(xié)議:GPL-2.0varch簡介varch(we-architecture,意為我們的框架庫)是嵌入式C語言常用代碼模塊庫,包含了嵌入式
    的頭像 發(fā)表于 09-04 08:06 ?505次閱讀
    一種常用<b class='flag-5'>嵌入式</b>開發(fā)<b class='flag-5'>代碼</b>庫

    七大嵌入式GUI盤點

    LCD設(shè)計提供高級支持,極大簡化了LCD設(shè)計。它是使用比較廣泛的一款GUI,配合GUI Builder或App Wizard上位機軟件,用起來也比較方便。emWin以C語言代碼提供,使其成為
    發(fā)表于 09-02 10:58

    嵌入式QT常見開發(fā)方式有哪些?

    嵌入式QT常見開發(fā)方式有哪些? 嵌入式工程師在學習和使用Qt進行開發(fā)時,常見的幾種開發(fā)方式包括: 1.Qt Widgets編程: 通過C++代碼直接編寫GUI應(yīng)用程序,利用QtWi
    發(fā)表于 08-12 10:05

    嵌入式系統(tǒng)怎么學?

    一系列課程和技術(shù),包括但不限于以下內(nèi)容: 1、基礎(chǔ)知識:學習計算機組成原理、數(shù)字電路、模擬電路等基礎(chǔ)知識,建立對計算機硬件的認知與理解。 2、編程語言:掌握至少一種嵌入式系統(tǒng)常用的編程語言,如
    發(fā)表于 07-02 10:10

    如何提升嵌入式編程能力?

    /C++:大多數(shù)嵌入式系統(tǒng)使用CC++編程語言,因此深入學習這兩種語言是非常重要的。 8. 理
    發(fā)表于 06-21 10:01

    ESP32C3編出來的組件靜態(tài)庫不完整是什么原因?

    最近從 ESP32切到了 ESP32C3,發(fā)現(xiàn) riscv編譯鏈編出來的組件不完整——例如 mbedtls組件,之前在 ESP32平臺、使用 xtensa編出來的libmbedtls.a有
    發(fā)表于 06-18 07:58

    C語言嵌入式開發(fā)中的關(guān)鍵編譯器角色

    嵌入式程序開發(fā)跟硬件密切相關(guān),需要使用C語言來讀寫底層寄存器、存取數(shù)據(jù)、控制硬件等,C語言和硬件之間由編譯器來聯(lián)系,一些
    發(fā)表于 04-26 14:53 ?653次閱讀
    <b class='flag-5'>C</b><b class='flag-5'>語言</b>:<b class='flag-5'>嵌入式</b>開發(fā)中的關(guān)鍵編譯器角色

    如何提升嵌入式C語言代碼可讀性

    接口是面向?qū)ο?b class='flag-5'>語言中的一個比較重要的概念,接口只對外部承諾實現(xiàn)該接口的實體可以完成什么樣的功能,但是不暴露實現(xiàn)的方式。這樣的好處是,實現(xiàn)者可以在不接觸接口使用者的代碼的情況下,對實現(xiàn)進行調(diào)整。
    發(fā)表于 04-11 11:30 ?363次閱讀
    如何提升<b class='flag-5'>嵌入式</b><b class='flag-5'>C</b><b class='flag-5'>語言</b><b class='flag-5'>代碼</b>可讀性

    如何成為一名嵌入式C語言高手?

    高手需要掌握C語言基礎(chǔ)、了解嵌入式系統(tǒng)的硬件架構(gòu)和工作原理,通過實踐項目提升技能,并積極參與開源項目和技術(shù)社區(qū)。持續(xù)學習和自我提升是成為嵌入式
    發(fā)表于 04-07 16:03

    如何成為一名嵌入式C語言高手?

    高手需要掌握C語言基礎(chǔ)、了解嵌入式系統(tǒng)的硬件架構(gòu)和工作原理,通過實踐項目提升技能,并積極參與開源項目和技術(shù)社區(qū)。持續(xù)學習和自我提升是成為嵌入式
    發(fā)表于 03-25 14:12

    嵌入式學習步驟

    開發(fā)。 嵌入式學習步驟總結(jié)如下: (1).確定目標平臺:選擇適合您要開發(fā)的嵌入式系統(tǒng)的硬件平臺。這取決于您要控制的設(shè)備以及您需要執(zhí)行的任務(wù)。 (2).選擇編程語言嵌入式系統(tǒng)通常使用
    發(fā)表于 02-02 15:24

    聊一聊嵌入式C語言

    作為一名嵌入式軟件開發(fā)者,熟練掌握嵌入式C語言對我的日常工作至關(guān)重要。
    的頭像 發(fā)表于 01-22 09:28 ?558次閱讀

    嵌入式自學好書推薦

    嵌入式自學好書推薦 在數(shù)字時代的浪潮中,嵌入式系統(tǒng)一直是數(shù)字電子產(chǎn)品中的重要組成部分。無論是家用電器、工業(yè)控制、汽車電子、醫(yī)療保健、軍事應(yīng)用還是物聯(lián)網(wǎng),嵌入式系統(tǒng)都無處不在,展現(xiàn)了廣闊的前景。隨著
    發(fā)表于 01-11 15:13
    主站蜘蛛池模板: 亲嘴扒胸摸屁股视频免费网站| 久久国产综合精品欧美| 亚洲中文字幕永久在线全国| 无码国产色欲XXXX视频| 日韩亚洲视频一区二区三区| 欧美日韩另类在线专区| 男人吃奶摸下弄进去好爽| 麻豆国产96在线日韩麻豆| 久久精品国产亚洲AV天美18| 九热这里只有精品| 久久草福利自拍视频在线观看| 精品无人区一区二区三区| 吉吉av电影| 精品一区二区三区在线成人| 久久99热成人精品国产| 久久强奷乱码老熟女| 久色乳综合思思在线视频| 美女扣逼软件| 欧美高清videossexo| 青青草伊人久久| 色爱区综合小说| 相声flash| 亚洲欧美日韩高清中文在线| 野花韩国高清完整版在线| 中文中幕无码亚洲在线| 999人在线精品播放视频| MM131亚洲精品久久安然| RAPPER性骚扰大开黄腔| 俄罗斯人与动ZOZ0| 国产亚洲精品久久久闺蜜| 久见久热 这里只有精品| 久久影院中文字幕| 女bbbbxxx孕妇| 色偷偷777| 亚洲精品视频在线观看免费| 御姐被吸奶| hd性欧美俱乐部中文| 国产精品免费大片| 久久88综合| 欧美一区二区三区激情视频| 涩涩在线视频|