3.5 统一名称

代码的主体是一个个的标志符,而标志符是由我们“随意”定义的,时间长了,别说他人阅读理解,估计自己都弄不清楚。清晰、统一的标志符是代码可审核的关键。

不同行业的产品,一般都有很多专用术语,为了方便交流,大家习惯性构建数据词典。如果能利用数据词典对代码标志符进行约定,标志符统一就迈出了第一步。

因用于变量定义,标志符希望起始字符是字母,但很多行业的术语经常是数字的,如电力行业用50表示速断过流,87表示差动。碰到这种情况,或者统一加前缀,或者换一套规范,如用OC代表速断过流,DIFF表示差动。

很多新人定义标志符时有一个不好的习惯,喜欢使用汉语拼音缩写。这类标志符比较反人性,阅读非常困难,因此,我们约定:除非有特定的行业习惯,原则上不允许使用汉语拼音缩写作为标志符

标志符命名,除了名词外,一般还会用到很多动词。英语词汇非常丰富,如果任由大家随意发挥,虽然可能用词更准确一点,但会给代码审核带来诸多困难。我们习惯限制可用的动词数量,尽可能使用普通的词汇,哪怕可能存在某种程度的词不达意也在所不惜,常用动词包括get/set,start/cancel,read/write等。通过数据词典,约定可用的动词,是一个良好的习惯。

大部分团队即使负责多款产品,但大多是同一专业方向,此时,不需要为每个产品构建单独的数据词典,可以一个团队甚至一个部门构建一份数据词典。这种策略也便于数据词典的持续迭代更新。

综上,我们约定:各团队必须构建数据词典以统一标志符命名

◇◇◇

典型的标志符命名有两种方式:驼峰命名法和unix命名法。网络上关于这两种命名法的口水不少,他们各有优缺点,团队内部统一即可。驼峰命名法又经常分为大驼峰和小驼峰,区别在于首字符是否大写。我们团队习惯使用小驼峰命名法。三种命名方式如下示意:

printEmployeePaychecks();	/* 小驼峰命名法 */
PrintEmployeePaychecks();	/* 大驼峰命名法 */
print_employee_paychecks();/* unix命名法 */

代码中不仅有很多变量定义,还有很多类型定义,如结构、联合、枚举等。为了区分,并结合小驼峰命名法,我们约定:所有的标志符首字母小写,所有的类型定义以大写字母起始,常量全大写且用下划线连接。为了进一步区分,我们习惯约定类增加C前缀,结构、联合或枚举增加T前缀

c语言中的类型定义是依赖于硬件的,如int在8位单片机和32位单片机长度可能不同,这个特性给程序带来了很多不确定性。为了规避这一问题,c99规范中的inttypes.h头文件为不同的整数类型提供了一套别名,如int32_t表示32位整数,int16_t表示16位整数。基于同样的理由,且为了满足所有类型定义以大写字母起始的约定,我们也给C语言基础数据类型定义了别名,如下:

类型 别名
32位无符号数 DWORD
32位有符号数 LONG
16位无符号数 WORD
16位有符号数 SHORT
8位无符号数 BYTE
8位有符号数 CHAR
单精度浮点数 FLOAT
双精度浮点数 DOUBLE

注:上述这套约定有歧义。这套约定我们团队已经用了十多年了,当时还受8086体系的影响,一个字是16位,因此16位无符号数用WORD,32位无符号数用D(ouble)WORD来表示。目前,主流嵌入式芯片都是基于arm-cortex芯片,其中一个字是32位。大家在定义别名时,需尽量规避这类歧义,推荐直接使用inttypes.h中定义,兼容性会更好一点。

◇◇◇

如果接触过早期MFC编程的程序员,应该都熟悉匈牙利命名法。

匈牙利命名法是一位叫Charles Simonyi的匈牙利程序员发明的,他后来进入微软工作,并参与了微软MFC类库的编写工作,因此潜移默化中影响到MFC团队的人,影响到微软的其他产品,更是随着微软产品影响到全球的程序员。

MFC类库中变量定义经常使用匈牙利命名法,基本原则为:变量名=属性+类型+对象描述+具体名称,其中每一属性,类型和对象都有明确的定义,经常是名字全称的缩写,具体名称部分以驼峰方式表现,每个单词的首字母大写。

如一个类成员窗口句柄类可能定义如下:m_hwndNewWinodow,其中m_表示类成员,h表示句柄,wnd表示窗口,综合起来m_hwnd就表示这是一个位于类空间的窗口句柄。

考虑匈牙利命名法的优缺点,且综合权衡嵌入式系统编程中经常需考虑字节对齐等特性,我们适度借鉴匈牙利命名法,仅对基本数据类型增加前缀。此时,汇总表如下:

类型 别名 前缀
32位无符号数 DWORD dw(i, j, k等常用循环子不加前缀)
32位有符号数 LONG n
16位无符号数 WORD w
16位有符号数 SHORT s
8位无符号数 BYTE by
8位有符号数 CHAR c
单精度浮点数 FLOAT f
双精度浮点数 DOUBLE lf
布尔 BOOL(TRUE, FALSE) b
句柄 HANDLE h
结构,联合,枚举 - T
- C
全局变量 - g_
类成员变量 - m_
文件内静态变量 - s_

◇◇◇

函数标志符有两种典型的命名风格,一种是动词+名词风格,便于阅读,一种是名词+动词风格,便于函数归类。如下所示:

/* 读取遥测值 */
FLOAT readAI(DWORD dwIndex);	/* 动词+名词风格 */
FLOAT AIRead(DWORD dwIndex);	/* 名词+动词风格 */

名称+动词风格最典型的就是ucos了,如下是所有的互斥信号量接口函数

OSMutexCreate(…);
OSMutexDel(…);
OSMutexPend(…);
OSMutexPendAbort(…);
OSMutexPost(…);

大家能否嗅到一点面向对象的特征,而且这种命名法,我们仅需要记住Mutex这个关键术语,借助编辑器,很容易查到mutex对应的所有接口函数。
在这里插入图片描述
c语言没有名字空间,如果类同ucos,给所有接口函数增加前缀,并按照体系架构分层划分,不像更高层次的面向对象吗。综上,我们约定:接口函数的命名风格为“层前缀+术语+动词”。

截取一段产品中的代码,便于大家理解基于这种约定的代码风格。

/* 硬件驱动层, 文件系统初始化 */
BOOL hwFileInit(void);

/* 硬件驱动层, 获取文件名字 */
LPCTSTR hwFileGetName(DWORD dwIndex);

/* 硬件驱动层, 文件读操作 */
BOOL hwFileRead(LPCTSTR lpszName, DWORD dwOffset, BYTE *pBuf, DWORD dwLen);

/* api层, 遥测模块初始化 */
void apiAIInit(void);

/* api层, 获取遥测值 */
float apiAIGet(DWORD dwIndex);

返回目录

——————————————

我是小马儿,一个渴望良知与灵魂的嵌入式软件工程师,欢迎您的陪伴与同行,如感兴趣可加个人微信号nzn_xiaomaer交流,需备注“异维”二字。

原创文章 32 获赞 36 访问量 9369

猜你喜欢

转载自blog.csdn.net/zhangmalong/article/details/104552678
3.5