zoukankan      html  css  js  c++  java
  • 痞子衡嵌入式:恩智浦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主页微信公众号 平台上。

    微信搜索"痞子衡嵌入式"或者扫描下面二维码,就可以在手机上第一时间看了哦。

  • 相关阅读:
    Apache、nginx 、lighttpd性能比较
    datapump
    ORA-0600
    在归档模式中,tablespace处于offline状态下,同样可以进行RMAN备份
    一个0级别增量备份小demo
    logminer
    statspack
    flashback table
    constraint
    linux进入单用户模式
  • 原文地址:https://www.cnblogs.com/henjay724/p/12495948.html
Copyright © 2011-2022 走看看