编码规范——华为篇

编码规范很重要,其实他直接影响到了代码迭代更新的效率和出问题的概率。以下为本人对网上广为流传的华为编码规范的个人总结。(ps:其中有几个原则实在是精辟的不能再精辟了,当然也有一些存在疑惑,还希望各位大佬不吝赐教)


1.不要使用难懂的技巧性很高的语句,除非很有必要时

高技巧语句不等于高效率的程序,实际上程序的效率关键在于算法。这可能是很多初学者最容易犯得错误。

2.去掉没必要的公共变量

公共变量是增大模块间耦合的原因之一。全局变量虽然好用,但是宜少不宜多这样能保证数据的安全性。

3.当向公共变量传递数据时,最好做数据合法性检查。

有必要最好做一下,因为万一出了问题是不好检测出来的。

4.构造仅有一个模块或函数可以修改、创建,而其余有关模块或函数只访问的公共变量,
防止多个不同模块或函数都可以修改、创建同一公共变量的现象

还是前面讲到的数据安全性问题,可以通过静态函数实现,且整个系统都要保持一致

5.仔细设计结构中元素的布局与排列顺序, 使结构容易理解、 节省占用空间, 并减少引起
误用现象

示例:如下结构中的位域排列,将占较大空间,可读性也稍差。
typedef struct EXAMPLE_STRU
{
unsigned int valid: 1;
PERSON person;
unsigned int set_flg: 1;
} EXAMPLE;
若改成如下形式,不仅可节省 1 字节空间,可读性也变好了。
typedef struct EXAMPLE_STRU
{
unsigned int valid: 1;
unsigned int set_flg: 1;
PERSON person ;
} EXAMPLE;

6.尽量减少没有必要的数据类型默认转换与强制转换。

7.对所调用函数的错误返回码要仔细、全面地处理

Linux系统里好像是不允许有空函数的

8.防止将函数的参数作为工作变量

将函数的参数作为工作变量, 有可能错误地改变参数内容, 所以很危险。 对必须改
变的参数,最好先用局部变量代之,最后再将该局部变量的内容赋给该参数。

示例:下函数的实现不太好。
void sum_data( unsigned int num, int *data, int *sum )
{
unsigned int count;
*sum = 0;
for (count = 0; count < num; count++)
{
*sum += data[count]; // sum 成了工作变量,不太好。
}
}
若改为如下,则更好些。
void sum_data( unsigned int num, int *data, int *sum )
{
unsigned int count ;
int sum_temp;
sum_temp = 0;
for (count = 0; count < num; count ++)
{
sum_temp += data[count];
}
*sum = sum_temp;
}

9.一个函数仅完成一件功能。

10.避免设计多参数函数,不使用的参数从接口中去掉。

目的减少函数间接口的复杂度,参数多的话可以通过结构体实现

11.非调度函数应减少或防止控制参数,尽量只使用数据参数

避免函数功能不明确,给调试带来麻烦

示例:如下函数构造不太合理。
int add_sub( int a, int b, unsigned char add_sub_flg )
{
if (add_sub_flg == INTEGER_ADD)
{
return (a + b);
}
else
{
return (a ٛ b);
}
}
不如分为如下两个函数清晰。
int add( int a, int b )
{
return (a + b);
}
int sub( int a, int b )
{
return (a ٛ b);
}

12.检查函数所有参数输入的有效性

功能不明确较小的函数,特别是仅有一个上级函数调用它时, 应考虑把它合并到上级
函数中, 而不必单独存在

13.设计高扇入、 合理扇出(小于7) 的函数。

函数较合理的扇出(调度函数除外) 通常是 3-5.较良好的软件结构通常是顶层函数的扇出较高, 中层函数的扇出较少, 而底层函数则扇入到公共模块中。还是强调函数的高复用性和可读性

14.避免使用BOOL参数

TURE/FALSE 的含义是非常模糊的,这点确实有点惊讶,对于那些内存要求不是很苛刻的能不用就不用吧

15.对于提供了返回值的函数, 在引用时最好使用其返回值。

16.当一个变量名较长且有较多引用时(一般是结构的成员), 可以用一个
意义相当的宏代替

也可以定义一个局部变量,在用之前对局部变量赋值

17.在同一项目组或产品组内, 调测打印出的信息串的格式要有统一的形式。 信息串中至少
要有所在模块名(或源文件名) 及行号

行号和文件名可以用宏__LINE__和__FILE__实现

18.使用断言来发现软件问题, 提高代码可测性。

断言可以对在系统中隐藏很深, 用其它手段极难发现的问题进行定位

示例:下面是 C 语言中的一个断言,用宏来设计的。(其中 NULL 为 0L)
#ifdef _EXAM_ASSERT_TEST_ // 若使用断言测试
void exam_assert( char * file_name, unsigned int line_no )
{
printf( "\n[EXAM]Assert failed: %s, line %u\n",
file_name, line_no );
abort( );
}
#define EXAM_ASSERT( condition )
if (condition) // 若条件成立,则无动作
NULL;
else // 否则报告
exam_assert( __FILE__, __LINE__ )
#else // 若不使用断言测试
#define EXAM_ASSERT(condition) NULL
#endif /* end of ASSERT */

19.在编写代码之前, 应预先设计好程序调试与测试的方法和手段, 并设计好各种调测开关
及相应测试代码如打印函数等

20.在保证软件系统的正确性、 稳定性、可读性及可测性的前提下, 提高代码效率。
 

21.避免循环体内含判断语句, 应将循环语句置于判断语句的代码块之中

笔者确实踩过这样的坑,并且真的很难发现是什么问题。另外循环嵌套尽量不要超过三层且不要太复杂。

22.尽量用乘法或其它方法代替除法,特别是浮点运算中的除法。

浮点运算除法要占用较多 CPU 资源。应为一般的cpu只有硬件乘法器

23.过程/函数中申请的(为打开文件而使用的)文件句柄,在过程/函数退出之前要关闭。

分配的内存不释放以及文件句柄不关闭, 是较常见的错误, 而且稍不注意就有可能发生。这类错误往往会引起很严重后果,且难以定位

24.有可能的话, if语句尽量加上else分支, 对没有else分支的语句要小心对待; switch
语句必须有default分支。

25.时刻注意表达式是否会上溢、 下溢。

示例:如下程序将造成变量下溢。
unsigned char size ;
while (size-- >= 0) // 将出现下溢
{
... // program code
}

26.打开编译器的所有警告开关对程序进行编译

27.某些语句经编译后产生警告,但如果你认为它是正确的,那么应通过某种手段去掉告
警信息

示例:
#pragma warn -rvl // 关闭告警
int examples_fun( void )
{
// 程序,但无 return 语句。
}
#pragma warn +rvl // 打开告警

28.使用代码检查工具(如C语言用PC-Lint)对源程序检查。使用软件工具(如 LogiSCOPE)进行代码审查

用过其中一个,效果不理想可能是不会用吧

29.不应通过“试” 来解决问题,应寻找问题的根本原因

最精辟的原则之一,可很多人就是通过“试”

30.对自动消失的错误进行分析,搞清楚错误是如何消失的

最精辟的原则之一,对于提高能力有很大帮助

你可能感兴趣的:(编码规范)