痞子衡嵌入式:恩智浦SDK驅動程式碼風格、模板、檢查工具
阿新 • • 發佈:2020-03-15
----
大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家講的是**恩智浦 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