你们好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给你们讲的是飞思卡尔软件开发C语言编码规范。node
2020鼠年春节是个漫长的假期,痞子衡在家百无聊赖,翻出了2016年10月1日(这个时间是痞子衡正式开始用markdown+github写技术文章并发表到博客园上的记念日)以前写的技术文档,不翻不知道,一翻吓一跳,从2007年上大学开始到2016年这十年间,我真的写了很是多的技术类文章,但都不够完整,没有成系统,排版上也不优雅,底下有时间我会慢慢整理出来,不能让之前的辛苦都被埋没了。
痞子衡2016年以前所写的那些技术文章除了原创外,也有一些是翻译的,好比今天要分享的这篇就是2013年痞子衡刚入职飞思卡尔半导体MCU软件团队时为了学习C编码规范所翻译的(外企嘛,各类资料都是洋文),当时飞思卡尔刚成立MCU软件团队不久,那时候Kinetis SDK也尚未正式推出,整个团队必需要有一个统一且良好的编码风格,这样写出来的SDK才符合大厂身份。废话很少说,下面是编码规范原文:git
制定此编码风格指导手册的目的是为了使按此规范编写出的C/C++代码极易被阅读和理解。github
- 须要以4个空格为单位的缩进.
- 坚定不用Tab键,要用空格键.
- 全部文件结尾必须空一行.
- 文本文件必须用UTF-8编码.
- 每一行不能超过100个字符.
- 恰当地进行代码注释.
- 关于注释长度没有具体限制,只要能提供帮助,就尽量地注释.
- 注释应该解释代码为何要这么作,而不是如何去作(代码自己已经代表了如何去作).
- 选择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、宏命名的基本规则,命名规则能够接受细微改动,但要保证在同一模块中的一致性:windows
- 全局函数名:全小写,单词用下划线隔开
如: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后缀
备注:切记不要用匈牙利命名法,由于其会致使变量名难于阅读,且类型前缀经常会与变量真正类型不一样步,微软曾是此命名法的拥趸,但其已意识到此命名法的缺陷,目前正在逐渐脱离此方法。markdown
- 一系列的整型常量应该用枚举来表示,而不是用宏来定义
1):在调试时,常量被显示为真实的标识,而不是数字
2):便于常量的逻辑分组- 大部分状况下,使用内联函数来代替宏功能
1):在调试中,内联函数能够被禁用,故能够跳过
2):内联函数参数有类型,而宏中参数不能够有类型
3):这个规则仅适用于当用宏来表示一段代码时,不适用于在表达式中表示某部分的宏
- 须要使用C99
C99被容许使能C++或C89语义内联- 在尽可能靠近变量被使用的地方来声明变量,而不是一概在函数顶部声明
1):这能够很容易地找到变量的定义
2):能够方便编译器进行优化- 单行注释应使用//而不是/* …*/
1):大部分人认为//式注释方便阅读
2):免去注释嵌套的烦恼- 多行注释/* …*/能够被用做大段肯定的内容注释,就像Doxygen注释头同样,以使得被注释的内容突出。
头文件中,内联功能启用应用static inline来完成并发
头文件中的公用函数原型必须包含在下列语句中函数
#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 (...) { }
代码风格基本遵守MISRA-C:20xx规范,但除了如下例外(这些例外是基于MISRA-C:2004规范的)
至此,飞思卡尔软件开发C语言编码规范痞子衡便介绍完毕了,掌声在哪里~~~
文章会同时发布到个人 博客园主页、CSDN主页、微信公众号 平台上。
微信搜索"痞子衡嵌入式"或者扫描下面二维码,就能够在手机上第一时间看了哦。