zoukankan      html  css  js  c++  java
  • 痞子衡嵌入式:知名半导体MCU大厂软件开发C代码规范


      大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家讲的是飞思卡尔软件开发C语言编码规范

      2020鼠年春节是个漫长的假期,痞子衡在家百无聊赖,翻出了2016年10月1日(这个时间是痞子衡正式开始用markdown+github写技术文章并发表到博客园上的纪念日)之前写的技术文档,不翻不知道,一翻吓一跳,从2007年上大学开始到2016年这十年间,我真的写了非常多的技术类文章,但都不够完整,没有成系统,排版上也不优雅,底下有时间我会慢慢整理出来,不能让以前的辛苦都被埋没了。
      痞子衡2016年之前所写的那些技术文章除了原创外,也有一些是翻译的,比如今天要分享的这篇就是2013年痞子衡刚入职飞思卡尔半导体MCU软件团队时为了学习C编码规范所翻译的(外企嘛,各种资料都是洋文),当时飞思卡尔刚成立MCU软件团队不久,那时候Kinetis SDK也还没有正式推出,整个团队必须要有一个统一且良好的编码风格,这样写出来的SDK才符合大厂身份。废话不多说,下面是编码规范原文:

    1.引言

      制定此编码风格指导手册的目的是为了使按此规范编写出的C/C++代码极易被阅读和理解。

    2.与其他编码风格对比

    3.基本排版格式

    • 需要以4个空格为单位的缩进.
    • 坚决不用Tab键,要用空格键.
    • 所有文件结尾必须空一行.
    • 文本文件必须用UTF-8编码.
    • 每一行不能超过100个字符.

    4.文档与注释

    • 恰当地进行代码注释.
    • 关于注释长度没有具体限制,只要能提供帮助,就尽可能地注释.
    • 注释应该解释代码为什么要这么做,而不是如何去做(代码本身已经表明了如何去做).
    • 选择Doxygen文档系统来完成注释,除了在函数中的注释之外(因为Doxygen不适用于个别代码行的注释),Doxygen也不适用于汇编.

    5.标准数据类型

    • 仅使用C99标准给出的整型(定义见stdint.h文件),如uint32_t,int16_t等,不要typedef自己的整型类型,如u8,int_32,WORD等.
    • 使用char 或wchar_t来表示字符串,但二进制缓存仍应使用uint8_t
    • 仅使用C99标准给出的bool型(定义见stdbool.h文件)来表示布尔变量,true和false表示其值. (ps: windows平台下编译时需自行定义,因为windows下不包含stdbool.h文件)

    6.标识符的命名

      以下是C/C++下变量、函数、typedef、宏命名的基本规则,命名规则可以接受细微改动,但要保证在同一模块中的一致性:

    • 全局函数名:全小写,单词用下划线隔开
      如:i2c_receive_data()
    • 普通变量名:Camel命名法
      如:thisIsMyVariable
    • 结构体名和类名:Pascal命名法
      如:BigBoxOfTools
    • 类成员函数名:Camel命名法
      如:initialLongProcess()
    • 用typedef重命名:全小写,单词用下划线隔开,加_t后缀
      如:big_box_of_tools_t
    • 用宏命名:单词全大写(仅在宏中使用,且必须使用)

      描述性强的,可读性强的变量名非常重要:

    • 大部分单词都不应该缩写,比如应用block而不是blk,应用count而不是cnt.
      一些流行的缩写还是允许的,如init或config
    • 完全可以接受较长的,描述性的变量名
    • 布尔型变量可以使用”is”,”did”等前缀,这会清晰地表明其是一个布尔型
    • 变量名应该可以表达其目的,但坚决反对匈牙利命名(加数据类型前缀)
      正确: temporaryParameters, startBlock, nodeKey, isAlarmEnabled
      错误:u32BlkNum, bEnabled

      有时候为了表明范围和目的,有些变量命名是可以加前缀和后缀的:

    • 局部变量:无需前缀
    • 全局变量:加g_前缀
    • 静态变量:加s_前缀
    • 类成员变量:加m_前缀
    • 常量:加k前缀
      1):如kUnconstrained, kFirstPage, kMaxBufferBytes
      2):k前缀使常量很容易被识别
    • typedef型变量:加_t后缀

      备注:切记不要用匈牙利命名法,因为其会导致变量名难于阅读,且类型前缀常常会与变量真正类型不同步,微软曾是此命名法的拥趸,但其已意识到此命名法的缺陷,目前正在逐渐脱离此方法。

    7.可调试性

    • 一系列的整型常量应该用枚举来表示,而不是用宏来定义
      1):在调试时,常量被显示为真实的标识,而不是数字
      2):便于常量的逻辑分组
    • 大部分情况下,使用内联函数来代替宏功能
      1):在调试中,内联函数可以被禁用,故可以跳过
      2):内联函数参数有类型,而宏中参数不可以有类型
      3):这个规则仅适用于当用宏来表示一段代码时,不适用于在表达式中表示某部分的宏

    8. C99标准

    • 需要使用C99
      C99被允许使能C++或C89语义内联
    • 在尽量靠近变量被使用的地方来声明变量,而不是一律在函数顶部声明
      1):这可以很容易地找到变量的定义
      2):可以方便编译器进行优化
    • 单行注释应使用//而不是/* …*/
      1):大部分人认为//式注释方便阅读
      2):免去注释嵌套的烦恼
    • 多行注释/* …*/可以被用作大段确定的内容注释,就像Doxygen注释头一样,以使得被注释的内容突出。

    9.内联功能

      头文件中,内联功能启用应用static inline来完成

    10. C/C++通用性

      头文件中的公用函数原型必须包含在下列语句中

    #if defined(__cplusplus)
    extern "C" {
    #endif // __cplusplus
    
    // 此处放函数原型
    
    #if defined(__cplusplus)
    }
    #endif // __cplusplus
    

      C中一般都用typedef来重命名结构体和枚举数据类型,不要提及原始的结构体或枚举型名
      C++中,则不需用typedef来重命名,直接用原始的结构体或枚举型名;但是如果代码被C/C++共享,则应遵从C风格
      对于被用在C++中的函数(比如类成员)而言,如果函数不带任何参数,则不需要一个专门的void参数来表明,而在C中这是需要的

    11.花括号的使用

      花括号的使用虽重要性不高,但经常起争议

    • 通常情况下,花括号应该单独起一行,不需要额外的缩进
    • 有时为了保持可读性,可以不遵守上一规则
    • 花括号使用的关键点在于不要将代码凑在一起,从而使得代码比较难阅读;也不要因为具体格式的限定,从而打破视觉流程

      使用规则可以接受细微改动,但要保证在同一模块中的一致性,以及易于阅读

    结构体和类示例:
    struct Monkey
    {
        int x;
    };
    
    typedef struct MonkeyTwo {
        int y;
    } monkey_two_t;
    
    class Cube
    {
    public:
        Cube(int theSize);
    
    private:
        int m_size;
    };
    枚举示例:
    enum _my_enum
    {
        kValueOne = 1,
        kValueTwo = 2
    };
    
    typedef enum _another {
        kAnotherOne = 10,
        kAnotherTwo = 20
    } another_t;
    函数示例:
    void foo()
    {
        printf("hi
    ");
    }
    If语句示例:
    if (baz >= kMaximumBaz)
    {
        baz = kMaximumBaz;
    }
    else if (!ready)
    {
        makeItReady();
    }
    else
    {
        abort();
    }
    For语句示例:
    for (i=0; i < 10; ++i)
    {
        printf("%d", i);
    }
    While语句示例:
    while (!done)
    {
        doSomething();
    }
    Do-while语句示例:
    do {
        doSomething();
    } while (!done);
    Switch语句示例:
    switch (value)
    {
        case 0:
            x += 1;
            break;
    
        case 1:
        {
            int y;
            calculateIt(&y);
            break;
        }
    
        default:
            return;
    }
    命名空间示例:
    namespace fsl
    {
    // Don't indent namespace contents!
    }
    Try-catch语句示例:
    try
    {
    }
    catch (std::exception & e)
    {
    }
    catch (...)
    {
    }
    

    12. 关于MISRA-C规范

      代码风格基本遵照MISRA-C:20xx规范,但除了以下例外(这些例外是基于MISRA-C:2004规范的)

      至此,飞思卡尔软件开发C语言编码规范痞子衡便介绍完毕了,掌声在哪里~~~

    欢迎订阅

    文章会同时发布到我的 博客园主页CSDN主页微信公众号 平台上。

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

  • 相关阅读:
    GL_TRIANGLE_FAN Vs GL_TRIANGLE_STRIP
    Color bleeding与caustics概念解析
    Two path ray tracing与Photon Mapping(粒子跟踪)
    右手定则判断法线方向
    正确使用atoi
    深入探讨透视投影坐标变换
    gluBuild2DMipmaps与glTexImage2D与glGenTexture()函数
    OpenGL纹理贴图流程
    int main( int argc, char ** argv)在VS2008中的配置的一个实例
    c++标准库中vector数组遍历时的用法
  • 原文地址:https://www.cnblogs.com/henjay724/p/12259328.html
Copyright © 2011-2022 走看看