1. 程式人生 > >痞子衡嵌入式:恩智浦SDK驅動程式碼風格、模板、檢查工具

痞子衡嵌入式:恩智浦SDK驅動程式碼風格、模板、檢查工具

----   大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家講的是**恩智浦 SDK 驅動的程式碼風格**。   上週痞子衡受領導指示,給 SE 同事做了一個關於 SDK 程式碼風格的分享。隨著組內新人的增多,這樣的培訓還是很有必要的。一是可以讓新同事通過程式碼風格來快速瞭解 SDK 驅動程式碼結構,另一方面也有利於新同事養成良好的編碼習慣。   痞子衡剛畢業時曾經也整理過一篇程式碼風格 [《飛思卡爾軟體開發C語言編碼規範》](https://www.cnblogs.com/henjay724/p/12259328.html),如今雖已是恩智浦紀元,但規範大多還是相似的,僅有微小更新。這次痞子衡將新版規範的要點提取了出來,並且還提供了標準模板,這樣大家學習起來更加方便。   另外鑑於領導指定我作為組內同事程式碼風格人肉審查員(大家寫好的程式碼需要由我人肉審查風格),這樣的工作如果真的完全是人工去做,可想而言有多枯燥和低效,因此痞子衡計劃寫一個配套的自動化檢查工具,暫且叫 MCUXpresso SDK Coding Style Checker,歡迎大家來圍觀這個專案。 > * 專案地址:https://github.com/JayHeng/MCUX-SDK-Coding-Style # mcux_sdk_coding_style ### 1.命名 #### 1.1 變數 變數命名使用 CamelCase (小駱駝峰法),即第一個單詞以小寫字母開始,第二個單詞以及後面的每一個單詞的首字母大寫,例如 myVariableName > * 作用域可在檔案外的全域性變數加 g\_ 字首,如 g\_myVariableName > * 使用 static 修飾的全域性變數加 s\_ 字首,如 s\_myVariableName > * 區域性變數不加任何字首,如 myVariableName > * 其他如 volatile, const 修飾或指標型變數,無需任何特殊表示 > * 命名中的大部分單詞都不要縮寫,除非是相當流行的縮寫,如 init 或 config #### 1.2 巨集 巨集命名使用下劃線命名法,單詞全大寫,例如 MY_MACRO_NAME #### 1.3 列舉 列舉型別的命名混合了多種命名法,且加了一些特殊前後綴 > * 列舉型別名使用下劃線命名法,單詞全小寫,且以下劃線開頭 > * 列舉元素名使用小駱駝峰法,但統一加 k 字首 > * 可用 typedef 重新命名列舉型別名,使用下劃線命名法,但需加 \_t 字尾 > * 列舉變數名使用小駱駝峰法 ```C typedef enum _my_enumeration_name { kMyEnumerator0 = 0x00U, kMyEnumerator1 = 0x01U, kMyEnumeratorEnd = 0x02U, } my_enumeration_name_t; static my_enumeration_name_t s_myEnumVariableName; ``` #### 1.4 結構體 結構體型別的命名混合了多種命名法,且加了一些特殊前後綴 > * 結構體型別名使用下劃線命名法,單詞全小寫,且以下劃線開頭 > * 結構體成員名使用小駱駝峰法 > * 可用 typedef 重新命名結構體型別名,使用下劃線命名法,但需加 \_t 字尾 > * 結構體變數名使用小駱駝峰法 ```C typedef struct _my_struct_name { uint32_t myStructMember0; uint32_t myStructMember1; } my_struct_name_t; static my_struct_name_t s_myStructVariableName; ``` #### 1.5 函式 函式命名使用 Pascal (大駱駝峰法),即把變數名稱的第一個字母也大寫,例如 MyFunctionName > * 函式命名可由 [Action][Module][Feature] 組成,動作在前,特性在後。如 InitDeviceClock() > * 一系列同類函式,可加 MODULE\_ 字首,字首單詞全大寫。如 SD 卡操作的系列函式,可為 SD_PowerOnCard()、SD_PowerOffCard() ### 2.程式碼體 #### 2.1 排版 > * 永遠不要使用 Tab 鍵(使用 4 個空格代替 Tab),需要以 4 個空格為單位的縮排 > * 換行符應使用 "unix"(LF),而不是windows(CR + LF) > * 檔案結尾需空一行 #### 2.2 花括號 不使用 K&R 風格花括號,左右括號都需要獨佔一行 #### 2.3 區域性變數定義 區域性變數定義應總是放在所在最小作用域(即最近的 {} 內)裡的最前面,並且一行程式碼僅定義一個變數 ```C void MyFunctionName(void) { uint8_t myVariableName0; uint8_t myVariableName1; /* 程式碼體 */ for (;;) { uint8_t myVariableName2; /* 程式碼體 */ } } ``` #### 2.4 數字 程式碼中所有無符號整型數字,均應加 "U" 字尾 ```text Hex: 0x1234ABCDU Dec: 1234U ``` #### 2.5 註釋 僅使用 /\* \*/ 來註釋 ```C /* 註釋風格1,單獨佔一行 */ uint8_t i = 0; for (; i < 5;) { i++; /* 註釋風格2,與程式碼共享一行 */ } ``` #### 2.6 條件編譯 \#endif 後面需要加如下注釋 ```C #if MY_MACRO_NAME /* 程式碼體 */ #endif /* MY_MACRO_NAME */ ``` #### 2.7 標頭檔案保護巨集 任何一個 .h 檔案都需要包含下面格式的標頭檔案保護巨集程式碼,巨集的命名與標頭檔案名保持一致。如檔名為 hello\_world.h,則巨集名為 \_HELLO\_WORLD\_H\_ ```C #ifndef _HEADER_FILENAME_ #define _HEADER_FILENAME_ /* 標頭檔案內容 */ #endif /* _HEADER_FILENAME_ */ ``` ### 3.整體模板 #### 3.1 原始檔(.c) ```C /* 包含標頭檔案程式碼 */ #include "template.h" /******************************************************************************* * Definitions ******************************************************************************/ /* 私有(僅本原始檔內使用)巨集、列舉、結構體的定義 */ #define MAX_DEVICES (128U) /******************************************************************************* * Variables ******************************************************************************/ /* 所有全域性變數(外部,靜態,常量,指標)的定義 */ uint32_t g_deviceIndex = 0; static device_config_t s_deviceConfig; const uint32_t g_maxDevices = MAX_DEVICES; static volatile uint8_t *s_deviceData; /******************************************************************************* * Prototypes ******************************************************************************/ /* 內部函式(即 static 修飾)的宣告 */ static uint32_t GetDeviceIndex(void); /******************************************************************************* * Code ******************************************************************************/ /* 所有函式(外部,內部)的定義 */ void InitDevice(void) { s_deviceConfig.index = 1; s_deviceConfig.mode = kDeviceMode1; memset(s_deviceConfig.data, 5, sizeof(s_deviceConfig.data)); s_deviceConfig.isEnabled = true; } static uint32_t GetDeviceIndex(void) { return s_deviceConfig.index; } int main(void) { InitDevice(); g_deviceIndex = GetDeviceIndex(); while (1) { } } ``` #### 3.2 標頭檔案(.h) ```C /* * Copyright xxx * All rights reserved. * * xxx License * * Revision History: * v1.0 - Description */ #ifndef _TEMPLATE_H_ #define _TEMPLATE_H_ /* 包含標頭檔案程式碼 */ #include #include #include /******************************************************************************* * Definitions ******************************************************************************/ /* 公共(可被其他原始檔使用)巨集、列舉、結構體的定義 */ enum _device_mode { kDeviceMode0 = 0x00U, kDeviceMode1 = 0x01U, kDeviceModeEnd = 0x02U, }; typedef struct _device_config { uint32_t index; uint32_t mode; uint8_t data[16]; bool isEnabled; } device_config_t; /* 外部全域性變數的宣告 */ extern uint32_t g_deviceIndex; extern const uint32_t g_maxDevices; /******************************************************************************* * API ******************************************************************************/ #if defined(__cplusplus) extern "C" { #endif /*_cplusplus*/ /* 外部函式(可加 extern 修飾)的宣告 */ void InitDevice(void); #if defined(__cplusplus) } #endif /*_cplusplus*/ #endif /* _TEMPLATE_H_ */ ``` ### 歡迎訂閱 文章會同時釋出到我的 [部落格園主頁](https://www.cnblogs.com/henjay724/)、[CSDN主頁](https://blog.csdn.net/Henjay724)、[微信公眾號](http://weixin.sogou.com/weixin?type=1&query=痞子衡嵌入式) 平臺上。 微信搜尋"__痞子衡嵌入式__"或者掃描下面二維碼,就可以在手機上第一時間看了哦。 ![](http://henjay724.com/image/github/pzhMcu_qrcode_258x2