痞子衡嵌入式:恩智浦SDK驅動程式碼風格、模板、檢查工具
- 2020 年 3 月 15 日
- 筆記
大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家講的是恩智浦 SDK 驅動的程式碼風格。
上周痞子衡受領導指示,給 SE 同事做了一個關於 SDK 程式碼風格的分享。隨著組內新人的增多,這樣的培訓還是很有必要的。一是可以讓新同事通過程式碼風格來快速了解 SDK 驅動程式碼結構,另一方面也有利於新同事養成良好的編碼習慣。
痞子衡剛畢業時曾經也整理過一篇程式碼風格 《飛思卡爾軟體開發C語言編碼規範》,如今雖已是恩智浦紀元,但規範大多還是相似的,僅有微小更新。這次痞子衡將新版規範的要點提取了出來,並且還提供了標準模板,這樣大家學習起來更加方便。
另外鑒於領導指定我作為組內同事程式碼風格人肉審查員(大家寫好的程式碼需要由我人肉審查風格),這樣的工作如果真的完全是人工去做,可想而言有多枯燥和低效,因此痞子衡計劃寫一個配套的自動化檢查工具,暫且叫 MCUXpresso SDK Coding Style Checker,歡迎大家來圍觀這個項目。
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 後綴
- 枚舉變數名使用小駱駝峰法
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 後綴
- 結構體變數名使用小駱駝峰法
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 局部變數定義
局部變數定義應總是放在所在最小作用域(即最近的 {} 內)里的最前面,並且一行程式碼僅定義一個變數
void MyFunctionName(void) { uint8_t myVariableName0; uint8_t myVariableName1; /* 程式碼體 */ for (;;) { uint8_t myVariableName2; /* 程式碼體 */ } }
2.4 數字
程式碼中所有無符號整型數字,均應加 "U" 後綴
Hex: 0x1234ABCDU Dec: 1234U
2.5 注釋
僅使用 /* */ 來注釋
/* 注釋風格1,單獨佔一行 */ uint8_t i = 0; for (; i < 5;) { i++; /* 注釋風格2,與程式碼共享一行 */ }
2.6 條件編譯
#endif 後面需要加如下注釋
#if MY_MACRO_NAME /* 程式碼體 */ #endif /* MY_MACRO_NAME */
2.7 頭文件保護宏
任何一個 .h 文件都需要包含下面格式的頭文件保護宏程式碼,宏的命名與頭文件名保持一致。如文件名為 hello_world.h,則宏名為 _HELLO_WORLD_H_
#ifndef _HEADER_FILENAME_ #define _HEADER_FILENAME_ /* 頭文件內容 */ #endif /* _HEADER_FILENAME_ */
3.整體模板
3.1 源文件(.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)
/* * Copyright xxx * All rights reserved. * * xxx License * * Revision History: * v1.0 - Description */ #ifndef _TEMPLATE_H_ #define _TEMPLATE_H_ /* 包含頭文件程式碼 */ #include <stdbool.h> #include <stdint.h> #include <string.h> /******************************************************************************* * 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_ */
歡迎訂閱
文章會同時發布到我的 部落格園主頁、CSDN主頁、微信公眾號 平台上。
微信搜索"痞子衡嵌入式"或者掃描下面二維碼,就可以在手機上第一時間看了哦。