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



  大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家講的是恩智浦 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主頁微信公眾號 平台上。

微信搜索"痞子衡嵌入式"或者掃描下面二維碼,就可以在手機上第一時間看了哦。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM