嵌入式C代码编写规范


文章来源

痞子衡嵌入式-知名半导体MCU大厂软件开发C代码规范

我觉得值得收藏和遵循,将要点排版一下转载到博客。

基本排版格式

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

文档和注释

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

标准数据类型

  • 仅使用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文件)

标识符的命名

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

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

Camel命名法:
* 第一个单词以小写字母开始
* 第二个单词的首字母大写或每一个单词的首字母都采用大写字母。

Pascal命名法:
* 相比 Camel 命名法,第一个单词首字母也大写。

描述性强的,可读性强的变量名非常重要:
* 大部分单词都不应该缩写,比如应用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后缀

可调试性

一系列的整型常量应该用枚举来表示,而不是用宏来定义

  • 在调试时,常量被显示为真实的标识,而不是数字
  • 便于常量的逻辑分组

大部分情况下,使用内联函数来代替宏功能

  • 在调试中,内联函数可以被禁用,故可以跳过
  • 内联函数参数有类型,而宏中参数不可以有类型
  • 这个规则仅适用于当用宏来表示一段代码时,不适用于在表达式中表示某部分的宏

C99标准

  • C99被允许使能C++或C89语义内联
  • 在尽量靠近变量被使用的地方来声明变量,而不是一律在函数顶部声明
  • 单行注释应使用//而不是/* …*/
  • 多行注释/* …*/可以被用作大段确定的内容注释,就像Doxygen注释头一样,以使得被注释的内容突出。
  • 头文件中,内联功能启用应用static inline来完成

C/C++通用性

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

#if defined(__cplusplus)
extern "C" {
#endif // __cplusplus

// 此处放函数原型

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

花括号的使用

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

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

结构体和类示例:
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\n");
}
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 (...)
{
}
  • 分享:
评论
还没有评论
    发表评论 说点什么