你們好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給你們講的是飛思卡爾軟件開發C語言編碼規範。node
2020鼠年春節是個漫長的假期,痞子衡在家百無聊賴,翻出了2016年10月1日(這個時間是痞子衡正式開始用markdown+github寫技術文章並發表到博客園上的記念日)以前寫的技術文檔,不翻不知道,一翻嚇一跳,從2007年上大學開始到2016年這十年間,我真的寫了很是多的技術類文章,但都不夠完整,沒有成系統,排版上也不優雅,底下有時間我會慢慢整理出來,不能讓之前的辛苦都被埋沒了。
痞子衡2016年以前所寫的那些技術文章除了原創外,也有一些是翻譯的,好比今天要分享的這篇就是2013年痞子衡剛入職飛思卡爾半導體MCU軟件團隊時爲了學習C編碼規範所翻譯的(外企嘛,各類資料都是洋文),當時飛思卡爾剛成立MCU軟件團隊不久,那時候Kinetis SDK也尚未正式推出,整個團隊必需要有一個統一且良好的編碼風格,這樣寫出來的SDK才符合大廠身份。廢話很少說,下面是編碼規範原文:git
制定此編碼風格指導手冊的目的是爲了使按此規範編寫出的C/C++代碼極易被閱讀和理解。github
- 須要以4個空格爲單位的縮進.
- 堅定不用Tab鍵,要用空格鍵.
- 全部文件結尾必須空一行.
- 文本文件必須用UTF-8編碼.
- 每一行不能超過100個字符.
- 恰當地進行代碼註釋.
- 關於註釋長度沒有具體限制,只要能提供幫助,就儘量地註釋.
- 註釋應該解釋代碼爲何要這麼作,而不是如何去作(代碼自己已經代表瞭如何去作).
- 選擇Doxygen文檔系統來完成註釋,除了在函數中的註釋以外(由於Doxygen不適用於個別代碼行的註釋),Doxygen也不適用於彙編.
- 僅使用C99標準給出的整型(定義見stdint.h文件),如uint32_t,int16_t等,不要typedef本身的整型類型,如u8,int_32,WORD等.
- 使用char 或wchar_t來表示字符串,但二進制緩存仍應使用uint8_t
- 僅使用C99標準給出的bool型(定義見stdbool.h文件)來表示布爾變量,true和false表示其值. (ps: windows平臺下編譯時需自行定義,由於windows下不包含stdbool.h文件)
如下是C/C++下變量、函數、typedef、宏命名的基本規則,命名規則能夠接受細微改動,但要保證在同一模塊中的一致性:windows
- 全局函數名:全小寫,單詞用下劃線隔開
如:i2c_receive_data()- 普通變量名:Camel命名法
如:thisIsMyVariable- 結構體名和類名:Pascal命名法
如:BigBoxOfTools- 類成員函數名:Camel命名法
如:initialLongProcess()- 用typedef重命名:全小寫,單詞用下劃線隔開,加_t後綴
如:big_box_of_tools_t- 用宏命名:單詞全大寫(僅在宏中使用,且必須使用)
描述性強的,可讀性強的變量名很是重要:緩存
- 大部分單詞都不該該縮寫,好比應用block而不是blk,應用count而不是cnt.
一些流行的縮寫仍是容許的,如init或config- 徹底能夠接受較長的,描述性的變量名
- 布爾型變量可使用」is」,」did」等前綴,這會清晰地代表其是一個布爾型
- 變量名應該能夠表達其目的,但堅定反對匈牙利命名(加數據類型前綴)
正確: temporaryParameters, startBlock, nodeKey, isAlarmEnabled
錯誤:u32BlkNum, bEnabled
有時候爲了代表範圍和目的,有些變量命名是能夠加前綴和後綴的:微信
- 局部變量:無需前綴
- 全局變量:加g_前綴
- 靜態變量:加s_前綴
- 類成員變量:加m_前綴
- 常量:加k前綴
1):如kUnconstrained, kFirstPage, kMaxBufferBytes
2):k前綴使常量很容易被識別- typedef型變量:加_t後綴
備註:切記不要用匈牙利命名法,由於其會致使變量名難於閱讀,且類型前綴經常會與變量真正類型不一樣步,微軟曾是此命名法的擁躉,但其已意識到此命名法的缺陷,目前正在逐漸脫離此方法。markdown
- 一系列的整型常量應該用枚舉來表示,而不是用宏來定義
1):在調試時,常量被顯示爲真實的標識,而不是數字
2):便於常量的邏輯分組- 大部分狀況下,使用內聯函數來代替宏功能
1):在調試中,內聯函數能夠被禁用,故能夠跳過
2):內聯函數參數有類型,而宏中參數不能夠有類型
3):這個規則僅適用於當用宏來表示一段代碼時,不適用於在表達式中表示某部分的宏
- 須要使用C99
C99被容許使能C++或C89語義內聯- 在儘可能靠近變量被使用的地方來聲明變量,而不是一概在函數頂部聲明
1):這能夠很容易地找到變量的定義
2):能夠方便編譯器進行優化- 單行註釋應使用//而不是/* …*/
1):大部分人認爲//式註釋方便閱讀
2):免去註釋嵌套的煩惱- 多行註釋/* …*/能夠被用做大段肯定的內容註釋,就像Doxygen註釋頭同樣,以使得被註釋的內容突出。
頭文件中,內聯功能啓用應用static inline來完成併發
頭文件中的公用函數原型必須包含在下列語句中函數
#if defined(__cplusplus) extern "C" { #endif // __cplusplus // 此處放函數原型 #if defined(__cplusplus) } #endif // __cplusplus
C中通常都用typedef來重命名結構體和枚舉數據類型,不要說起原始的結構體或枚舉型名
C++中,則不需用typedef來重命名,直接用原始的結構體或枚舉型名;可是若是代碼被C/C++共享,則應聽從C風格
對於被用在C++中的函數(好比類成員)而言,若是函數不帶任何參數,則不須要一個專門的void參數來代表,而在C中這是須要的學習
花括號的使用雖重要性不高,但常常起爭議
- 一般狀況下,花括號應該單獨起一行,不須要額外的縮進
- 有時爲了保持可讀性,能夠不遵照上一規則
- 花括號使用的關鍵點在於不要將代碼湊在一塊兒,從而使得代碼比較難閱讀;也不要由於具體格式的限定,從而打破視覺流程
使用規則能夠接受細微改動,但要保證在同一模塊中的一致性,以及易於閱讀
結構體和類示例: struct Monkey { int x; }; typedef struct MonkeyTwo { int y; } monkey_two_t; class Cube { public: Cube(int theSize); private: int m_size; }; 枚舉示例: enum _my_enum { kValueOne = 1, kValueTwo = 2 }; typedef enum _another { kAnotherOne = 10, kAnotherTwo = 20 } another_t; 函數示例: void foo() { printf("hi\n"); } If語句示例: if (baz >= kMaximumBaz) { baz = kMaximumBaz; } else if (!ready) { makeItReady(); } else { abort(); } For語句示例: for (i=0; i < 10; ++i) { printf("%d", i); } While語句示例: while (!done) { doSomething(); } Do-while語句示例: do { doSomething(); } while (!done); Switch語句示例: switch (value) { case 0: x += 1; break; case 1: { int y; calculateIt(&y); break; } default: return; } 命名空間示例: namespace fsl { // Don't indent namespace contents! } Try-catch語句示例: try { } catch (std::exception & e) { } catch (...) { }
代碼風格基本遵守MISRA-C:20xx規範,但除了如下例外(這些例外是基於MISRA-C:2004規範的)
至此,飛思卡爾軟件開發C語言編碼規範痞子衡便介紹完畢了,掌聲在哪裏~~~
文章會同時發佈到個人 博客園主頁、CSDN主頁、微信公衆號 平臺上。
微信搜索"痞子衡嵌入式"或者掃描下面二維碼,就能夠在手機上第一時間看了哦。