大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家講的是恩智浦 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主頁、微信公眾號 平台上。
微信搜索"痞子衡嵌入式"或者掃描下面二維碼,就可以在手機上第一時間看了哦。