《编码规范和测试方法——C/C++版》学习笔记 ·002

文章目录

一、相关知识补充

1、switch接受的参数类型

switch接受的参数实际上是整型int,但是许多其他类型都可以被隐式转换为整型,所以这一点不是很明显。

2、内存分区与数据存放

如下图所示:
内存的四个分区
上述内存分区中,栈区的大小往往比堆区小很多,因此不宜在栈区申请过大的数组等。

当一个指针在堆区动态申请到一些空间时,相当与获得了堆区内存的访问权限,因此没有被申请的空间是无法访问的。

  • 如果指针指向一个未被申请/已被释放的地址,则无权限访问,称为指针悬挂,这样的指针称为野指针
  • 如果指针之前申请的空间未被收回,又更换了指向,则之前申请的内存将无法被别人访问,称为内存泄漏

3、变量的作用域与生命期

局部变量的作用域在代码块内,生命期持续到代码块调用结束。

全局变量的作用域是整个程序,生命期持续到程序执行结束。

堆区变量的生命期从申请内存空间开始,持续到释放内存空间结束。

4、调试开关的使用

调试开关主要通过#if#ifdef#ifndef等预编译指令来实现。

二、规范事项

1、杂项

(1).for循环语句中只出现影响循环控制的变量

像下面这段代码中,num即为无关变量,定义、初始化可以放到for循环上面,num的迭代可以放到for循环里面。

for (int i = 0, num = 10; i < 5; ++i, ++num)

(2).不要比较指针类型的变量

指针变量的比较除了在数组里可能有意义,在其他大部分时候是没有意义的。

(3).不要在sizeof运算符中使用自增自减

增强可读性,避免出错。

(4).逻辑表达式中的每一个逻辑判断都加上括号

勤加括号,避免混淆不同运算符的优先级。

2、循环语句的效率

(1).对不同的情况使用适当的循环体

  • 有明确循环次数,一般选择for循环
  • 没有明确循环次数,一般选择while循环
  • 至少循环1次,一般选择do while循环

(2).建议for循环采用“左闭右开区间”写法

不建议写成以下形式:

for (int i = 0; i <= 4; ++i)

建议写成以下形式:

for (int i = 0; i < 5; ++i)

(3).建议将高循环次数的循环置于嵌套循环的最内层

可以减少CPU跨切循环层的次数,从而优化程序性能。

(4).建议将高循环次数的循环体内的逻辑判断移到循环体外

3、if语句

(1).if语句独占一行,执行语句不得紧跟其后

(2).无论有几条执行语句,都要用大括号将执行语句括起来

便于以后的维护。

(3).else-if语句一定要包含最后的else节

增强可读性,避免出错。

4、switch语句

(1).switch语句独占一行

(2).每个case独占一行,执行语句不得紧跟其后

(3).若某个case没有break需要给出确认性注释

避免漏加而出错

(4).一定要有default语句

使switch语句完整。

(5).真假两种处理不应采用switch语句,应采用if语句

(6).case语句的先后顺序要使得执行次数尽可能少

各个case的顺序尽可能从以下顺序中选择有效的:

  • 按出现频率的顺序,将频繁出现的处理放在前面
  • 按照常见性的顺序,从通常的case到例外的case
  • 按数值或字母的顺序

5、for语句

(1).for语句独占一行,执行语句不得紧跟其后

(2).无论有多少条执行语句,都必须用大括号将执行语句括起来

便于以后的维护。

(3).空的循环体要给出确认性注释

(4).循环计数尽量从0开始,不要从1开始。

(5).不要在循环体内强制变更循环变量

增强可读性,避免出错。

(6).for循环中禁用逗号运算符

增强可读性,避免出错。

(7).尽量避免在循环内申请/释放内存

防止产生内存泄漏。

6、while语句

(1).while语句独占一行,执行语句不得紧跟其后

(2).无论多少条语句都要用大括号将执行语句括起来

便于以后的维护。

(3).空的循环体要给出确认信解释

7、return语句

(1).return语句的返回值类型和函数声明的返回值类型相同

类型不同的时候可能会触发一个隐式强制类型转换。

但是在有些时候,将范围大的类型转换成范围小的类型时,会产生高位截断,如以下代码:

#include <cstdio>

char func()
{
	int a = 0x1010;
	return a;
}

int main()
{
	char ch = func();
	printf("%#x", ch);  // 0x10

	return 0;
}

(2).void返回值的函数return语句不应该有返回值

(3).建议一个函数一条返回语句

不建议使用下面的格式:

int func()
{
	int a = 100;
	
	if (a > 50)
		return 100;
	else
		return 0;
}

建议使用下面的格式:

int func()
{
	int res;
	int a = 100;

	if (a > 50)
		res = 100;
	else
		res = 0;

	return res;
}

(4).禁止使用goto语句

goto语句往往会破坏代码的执行结构,让代码难以理解,除了极少数的特殊的适用场景下,很少会用到。

有一种场景就是多个变量动态申请内存空间。

  • 一开始的代码如下,这样写存在内存泄漏的问题,如果q申请空间失败,p的内存没有回收,就会有内存泄漏。
    int func()
    {
    	int *p, *q;
    
    	p = (int*)malloc(4 * sizeof(int));
    	if (NULL == p)
    	{
    		printf("malloc fail\n");
    		return 0;
    	}
    
    	q = (int*)malloc(4 * sizeof(int));
    	if (NULL == q)
    	{
    		printf("malloc fail\n");
    		return 0;
    	}
    
    	return 1;
    }
    
  • 因此,需要一个统一的申请失败终点,如以下代码
    int func()
    {
    	int *p, *q;
    
    	p = (int*)malloc(4 * sizeof(int));
    	if (NULL == p)
    	{
    		printf("malloc fail\n");
    		goto End;
    	}
    
    	q = (int*)malloc(4 * sizeof(int));
    	if (NULL == q)
    	{
    		printf("malloc fail\n");
    		goto End;
    	}
    
    	return 1;
    
    End:
    	if (NULL == p)
    	{
    		free(p);
    	}
    	if (NULL == q)
    	{
    		free(q);
    	}
    	return 0;
    }
    

类似的场景还有文件的打开。

8、初始化

(1).在enum类型中,将成员全部初始化/都不初始化/只初始化最前连续的几个

(2).初始化所有指针变量

9、代码格式

(1).函数的参数一般不要超过7个

从汇编角度来看,函数有4个参数时传递效率最高,因为在不超过4个参数的时候是通过寄存器来传递参数的,超过了就得借助栈空间来传递。

当参数过多时,应该考虑将参数定义为一个结构体,并将结构体指针作为参数

(2).函数的大小不要过长,一般定为350行以内(去除注释、变量定义、调试开关)

提高可读性,便于以后的维护,遵循函数设计原则。

(3).嵌套语句需要4字符的缩进

(4).用空行将代码逻辑片段进行划分

增加可读性。

(5).存储类型应该紧跟类型,而不是变量

存储类型有auto、static等。

举个例子,应该使用static int a;而不是int static a;

(6).在声明和定义处,将指针、引用[*, &]紧跟类型,而不是变量

在这一点往往不同的公司要求不同。举个例子,一种是int* a,另一种是int *a;

10.函数

(1).数组作为函数参数时,不需要指定数组大小

数组作为参数传递的是首地址,因此指定数组大小也是没有意义的。

(2).内定数据类型作为参数时,如果不需要修改就作为值传递而不是引用传递

(3).使用标准库<ctype.h>或<cctype>里的函数进行字符判断

提高代码效率,使代码更加精简。

(4).函数的声明和定义里参数标识应该保持一致

(5).禁止函数返回局部变量的指针或引用

发布了49 篇原创文章 · 获赞 9 · 访问量 3121

猜你喜欢

转载自blog.csdn.net/qq_44220418/article/details/104496052
002
今日推荐