编写零漏洞代码所需编码准则
1、数组下标应从0开始
- 编程菜鸟才会出错,这里就不多说了。
2、置换字符串时必须使用括号
- 也是编程菜鸟会犯错,就不多说了
懂得都懂
#define S(x) (x*x) //s(x)=x*x
3、文件必须有开就有关
-
之前听主管过这样一件事,他负责的项目在快收尾的时候,进行了综合测试,但很奇怪,只有她编写的程序出错了,各种检查,1500行代码,花费两周时间,居然没找出异常!!!
-
延期赔偿金,时间。。。最后他在一个非常小的程序里找到了原因,不知哪个菜鸟程序员,在打开文件后,没有关闭,导致我没有权限再次读。
-
他只要加一行fclose(masterFp);就不会把项目延期两周,赔偿金也不用赔付了。
-
细节问题。文件打开后会一直读,即使没有读到东西也要加一行代码去关闭。
4、不要无视编译器的警告错误
- 致命错误(fatal error)
- 警告错误(warning error)
- 致命错误通常指,如果不修复错误,程序就无法运行。偶尔也会有些致命错误不影响程序运行,但会在运行中产生问题。所以做好在测试过程中查找。
- 警告错误或许不会引起什么重大问题,或者说根本不会产生问题。但是我们仍然不能轻视。之前在做单元测试的时候,忽视了一些警告错误,最后工作的时候居然发生了系统瘫痪。经过各种分析,最后才发现是存储位置一处、文件混乱,最后导致整个系统瘫痪—缓冲溢出(数据溢出)。
5、掌握并在编码时防止运行时错误
程序运行过程中出现的错误称为运行时错误,这种错误不同于编译错误和逻辑错误。
- 编译错误主要由语法引起
- 逻辑错误主要是程序逻辑或算法的设计缺陷引发的
- 运行时错误则与运行时的环境有关
下面介绍两种常见的运行时错误
5.1 栈溢出
- 栈溢出是由于操作系统限制栈的大小而产生的,也就是说,各操作系统对栈的大小设置都不一样。
- 虽然一部分操作系统可以让用户调整栈的大小,但处理大容量数据时仍可能发生栈溢出。
- 在使用大数组的情况下,可能会发生栈溢出。使用非常大的数组,会占用栈的大部分空间,可供其他自动变量存储的空间就相对不足。
- 使用递归函数时,我们一定要细致检查栈溢出的可能性根据递归终止条件,来判断是否发生栈溢出。
5.2 除以0
在复杂的代码中,可能出现除数偶然为0的情况。
- 假如需要编写一个处理输入值的程序,该程序的输入值最小为1.一旦程序员忘记规定,用户输入了0用作出发计算,那么就会触发错误
- 在控制语句中,如for、while语句,用计算循环次数的变量(计数器)作为出书,与其他变量做除法运算。也会出发错误。
这些错误往往潜藏在复杂逻辑中,很难把握。这就要求程序员要细致检查程序所有可能的运行情况。
6、用静态变量声明大数组
c语言根据变量的生存周期、影响范围和存储位置的不同,将变量分为如下几类:
变量修饰符 | 变量名 | 存储位置 |
---|---|---|
extern | 外部变量 | 存储于堆 |
static | 静态变量 | 存储于堆 |
auto | 自动变量 | 存储于堆 |
register | 寄存器变量 | 存储与CPU的寄存器 |
- 处理大量数据,通常会使用数组。
int arr[100][100][100]//存放在栈空间
static int arr[100][100][100]//存放在堆空间
- 数组存放在堆空间就不会发生溢出
7、预留足够的存储空间
- 用户用数组存储字符串,假设要输入的长度为80个字符,那么定义时就应该预留2~3倍甚至更多字符串存储空间。
char inputString[800];//预留的存储空间大小是与其输入长度的10倍
- 有人说浪费存储空间。但是但你实际工作过程中,一旦输入的内容超过80给字符串,就会直接导致程序错误。
- 因此,我们应该实现检查输入字符串的长度、内容是否在有效范围内。
8、注意信息交换引发的涌现效果
8.1 什么词汇??
- 程序单元之间进行信息交换的过程中,可能引发用涌现性。
- 涌现性指的是能够引起意想不到的效果的实质,是复杂系统相关研究领域非常常见的词汇。
- 也就是程序在运行过程中,会发生难以意料的bug,通过代码可能检测不出来的bug。。。
8.2 how预防?
进行系统层面的综合测试
例如:
- 把包含10个互相联系的程序单元称为综合系统,首先在这一层级进行综合测试
- 任何将这种系统局纪委整个软件系统,在该层级在此进行综合测试
- 之后将其应用于业务,再人机交互阶段再次进行严格的综合测试
- 通过这几步,可以在一定程度上发现并预防涌现性现象,但这要求在测试过程中投入于软件开发同样多的资源。
9、小结
我也是一边写一边学习,说实话,确实学到了很多编码规则,慢慢地,相信我也能写一手规范的代码。加油!!!