最近开始在阅读陈正冲编著的《C 语言深度解剖》,还没读到十分之一就感觉收获颇多。其中印象比较深刻的是其中的变量的命名规则。
里面提到的不允许使用拼音正是我有时候会犯的错。
因为在以往的工作中,偶尔会遇到时间紧迫的情况。
而对于新增加的变量不知道该用什么英文单词命名,为了赶时间,就用拼音代替。殊不知这是一个很不好的习惯。
一般规则:
**【规则 1-1】**命名应当直观且可以拼读,可望文知意,便于记忆和阅读。
标识符最好采用英文单词或其组合,不允许使用拼音。程序中的英文单词一般不要太复杂,用词应当准确。
这个很好理解,比如要用int整型定义一个矩形框的长,就用int width。
**【规则 1-2】**命名的长度应当符合“min-length && max-information”原则。C 是一种简洁的语言, 命名也应该是简洁的。例如变量名 MaxVal 就比MaxValueUntilOverflow 好用。标识符的长度一般不要过长,较长的单词可通过去掉“元音”形成缩写。另外,英文词尽量不缩写,特别是非常用专业名词,如果有缩写,在同一系统中对同一单词必须使用相同的表示法,并且注明其意思。
“min-length && max-information” 原则是指在信息传递的过程中,文本长度应该尽可能短,但是不能牺牲信息的准确性和完整性。这个原则体现了在信息传递中精简和有效的文本表达的重要性。
短文本可以更快地阅读和理解,同时也可以在有限的空间内更好地传达信息。然而,为了保证信息准确性和完整性,有时需要使用较长的文本。因此,在编写文本时,应该将准确和完整的信息作为首要考虑因素,并尽可能简洁明了地表达出来。
这个原则可以通过有效的排版、优化的语言和有意义的标题来实现。通过使用这种最小长度和最大信息的原则,可以提高信息传递的效率和效果,使文本更易读和理解。
**【规则 1-3】**当标识符由多个词组成时,每个词的第一个字母大写,其余全部小写。比如:int CurrentVal;这样的名字看起来比较清晰,远比一长串字符好得多。
这个规则其实各大语言本身系统语句都在遵循,比如Qt的setWindowFlags,GetSystemMetrics,在命名变量名的时候,即便是再忙也要花时间去规范命名。如果为了方便,短时间还好,时间一长,代码量一大,或者将源代码给同事看的时候,估计都是一头雾水。
**【规则 1-4】**尽量避免名字中出现数字编号,如 Value1,Value2 等,除非逻辑上的确需要编号。比如驱动开发时为管脚命名,非编号名字反而不好。初学者总是喜欢用带编号的变量名或函数名,这样子看上去很简单方便,但其实是一颗颗定时炸弹。这个习惯初学者一定要改过来。
对于这个规则,在才开始工作做的第一个软件时就犯过错,在使用Qt的时候在UI界面新增控件时,编辑器会根据当前UI上的情况自己给控件创建名称。比如拉3个按钮控件,若UI界面上已经有两个被默认命名的按钮控件名pushButton,pushButton_2,那么这3个控件将会被命名为pushButton_3,pushButton_4,pushButton_5。虽然在UI界面新拉控件的时候很爽,咔咔咔半天时间就能做好一个界面。但真正开始对每个控件写事件,写槽函数的时候就会反复的回到UI界面,看这个按钮当时是setText的什么名字。这个习惯在第二个软件时有所改变。但是基于软件的性质,还是难免会出现数字编号。比如第二个软件所涉及到的下位机有40个通道,每个通道需要对应一组控件,在对这一组控件命名时就得加上通道号。
【规则 1-5】对在多个文件之间共同使用的全局变量或函数要加范围限定符(建议使用模块名
(缩写)作为范围限定符)。(GUI_ ,etc)
这个用到的比较少,是因为在工作中本人不是很喜欢定义全局变量。一般喜欢通过定义一个类专门来储存需要全局使用的变量。然后在这个类的public中定义,在需要引用全局变量的头文件中include这个类就行。我现在还不确定这种方式的优劣,等到我开始系统性学习C++的时候会重点关注这些知识点。
标识符的命名规则:
**【规则 1-6】**标识符名分为两部分:规范标识符前缀(后缀) + 含义标识 。非全局变量可以
不用使用范围限定符前缀。
**【规则 1-7】**作用域前缀命名规则。
No. | 标识符类型 | 作用域前缀 |
---|---|---|
1 | Global Variable | g |
2 | File Static Variable(native) | n |
3 | Function Static Variable | f |
4 | Auto Variable | a |
5 | Global Function | g |
6 | Static Function | n |
**【规则 1-8】**数据类型前缀命名规则。
No. | Prefix | Suffix | Data Type | Example | Remark |
---|---|---|---|---|---|
1 | bt | bit | Bit btVariable; | ||
2 | b | boolean | boolean bVariable; | ||
3 | c | char | char cVariable; | ||
4 | i | int | int iVariable; | ||
5 | s | short[int] | short[int] sVariable; | ||
6 | l | long[int] | long[int] lVariable; | ||
7 | u | unsigned[int] | unsigned[int] uiVariable; | ||
8 | d | double | double dVariable; | ||
9 | f | float | float fVariable; | ||
10 | p | pointer | void *vpVariable; | 指针前缀 | |
11 | v | void | void vVariable; | ||
13 | st | enum | enum A stVariable; | ||
14 | st | struct | struct A stVariable; | ||
15 | st | union | union A stVariable; | ||
16 | fp | function point | void(* fpGetModeFuncList_a[])( void ) | ||
17 | _a | array of | char cVariable_a[TABLE_MAX]; | ||
18 | _st_pst | typedefenum/struct/union | typedef struct SM_EventOpt { unsigned char unsigned int char}SM_EventOpt_st,*SM_EventOpt_pst; | 当自定义结构数据类型时使用_st 后缀;当自定义结构数据类型为指针类型时使用_pst后缀; |
**【规则 1-9】**含义标识命名规则,变量命名使用名词性词组,函数命名使用动词性词组。
No | 变量名 | 目标词 | 动词(的过去分词) | 状语 | 目的地 | 含义 |
---|---|---|---|---|---|---|
1 | DataGotFromSD | Data | Got | From | SD | 从 SD 中取得的数据 |
2 | DataDeletedFromSD | Data | Deleted | From | SD | 从 SD 中删除的数据 |
变量含义标识符构成:目标词 + 动词(的过去分词)+ [状语]+[目的地];
No | 变量名 | 目标词 | 动词(的过去分词) | 状语 | 目的地 | 含义 |
---|---|---|---|---|---|---|
1 | GetDataFromSD | Data | Get | From | SD | 从 SD 中取得的数据 |
2 | DeleteDataFromSD | Data | Delete | From | SD | 从 SD 中删除的数据 |
函数含义标识符构成:动词(一般现时)+目标词+[状语]+[目的地];
**【规则 1-10】**程序中不得出现仅靠大小写区分的相似的标识符。
例如:int x, X; 变量 x 与 X 容易混淆
void foo(int x); 函数 foo 与 FOO 容易混淆
void FOO(float x);
这里还有一个要特别注意的就是 1(数字 1)和 l(小写字母 l)之间,0(数字 0)和 o
(小写字母 o)之间的区别。这两对真是很难区分的,我曾经的一个同事就被这个问题折腾
了一次。
**【规则 1-11】**一个函数名禁止被用于其它之处。
//例如:
#include "c_standards.h"
void foo(int p_1)
{int x = p_1;
}
void static_p(void)
{int foo = 1u;
}
**【规则 1-12】**所有宏定义、枚举常数、只读变量全用大写字母命名,用下划线分割单词。
例如:
const int MAX_LENGTH = 100; //这不是常量,而是一个只读变量,具体请往后看
#define FILE_PATH “/usr/tmp”
**【规则 1-13】**考虑到习惯性问题,局部变量中可采用通用的命名方式,仅限于 n、i、j 等作
为循环变量使用。
一定不要写出如下这样的代码:
int p;
char i;
int c;
char * a;
一般来说习惯上用 n,m,i,j,k 等表示 int 类型的变量;c,ch 等表示字符类型变量;a 等表
示数组;p 等表示指针。当然这仅仅是一般习惯,除了 i,j,k 等可以用来表示循环变量外,别
的字符变量名尽量不要使用。
**【规则 1-14】**定义变量的同时千万千万别忘了初始化。定义变量时编译器并不一定清空了
这块内存,它的值可能是无效的数据。
**【规则 1-15】**不同类型数据之间的运算要注意精度扩展问题,一般低精度数据将向高精度
数据扩展。