目录
规范8:【释放结构体/数组/各类数据容器指针前,必须先释放成员指针】
规范10:【使用循环变量必须初始化,防止出现随机数,导致死循环】
规范12:【当给字符串分配空间、字符串复制时,一定要给结尾标志空字符’\0’留出空间】
规范14:【字符串拷贝时,一定要注意目标字符串的长度是否足够】
规范17:【当声明用于分布式环境或不同CPU间通信环境的数据结构时,必须考虑机器的字节顺序、使用的位域及字节对齐等问题】
规范19:【运算符使用必须加括号进行保护,禁止使用默认优先级】
规范25:【多线程编程,对于要求线程安全的变量、函数、资源,必须加锁保护,避免出现两个任务访问异常,导致内存越界】
1 内存管理
规范1:【内存使用必须遵循谁申请谁释放原则】
说明:谁申请内存,理应由申请人发起释放内存的动作,依赖他人释放内存,难以得到保证,导致内存泄露的可能增加。
规范2:【内存释放函数和该内存的申请函数必须配套使用】
说明:函数中分配内存,内存释放和申请必须要配套,注意在函数的各个返回分支都要释放,特别是异常分支处理也不要遗漏,避免内存出现泄露。
错误示例:
...
char *data = (char *)malloc(mem_size);
...
if (errno) {
return;
}
正确示例:
...
char *data = (char *)malloc(mem_size);
...
if (errno) {
goto error; >>>修正方案,出现错误时,跳转到错误处理分支释放资源
}
error:
if (data != NULL) {
free(data);
}
规范3:【申请内存后必须要先判断内存有效性】
说明内存申请时,可能出现不可预知的事情,避免对申请失败的内存进行写操作。申请内存后必须要先判断内存的有效性,再对其进行操作。
引申:申请任何资源都必须进行有效性判断后再使用,包换但不限于数据库资源池、共享内存等。
错误示例:
char *outbuf = (char *)malloc(100);
memset(outbuf, 0, 100);
......
正确示例:
char *outbuf = malloc(100);
if (NULL == inbuf){
error("Could not allocate outbuf bufer");
return 0;
}
memset(outbuf, 0, 100);
......
规范4:【内存拷贝前必须进行长度有效性判断,避免内存越界】
引申:避免使用魔鬼数字来进行人工计算字符长度,引起内存越界。(魔鬼数字的定义:在代码中没有具体含义的数字、字符串。)
错误示例:
memcpy(dst_addr, src_addr, paramlen);
说明:paramlen是其他模块传过来的参数,是可变长的
修正方案:
先判断paramlen长度,避免超过dst_addr指向空间的长度。
正常情况下,其他模块传过来的参数是正常的,不会有问题;
异常情况下,如果其他模块传过来的长度超长,则会发生内存越界,导致系统异常。
规范5:【禁止引用已经释放的内存空间】
说明:内存释放后,如果再引用将导致不可预知的错误。
错误示例:
char* c;
std::string s="1234";
c = s.c_str();
c最后指向的内容是垃圾,因为s对象被析构,其内容被处理
正确示例:
char c[20];
std::string s="1234";
strcpy(c, s.c_str());
这样才不会出错,c_str()返回的是一个临时指针,不能对其进行操作
2 指针管理
规范6:【指针使用前必须进行有效性判定,避免使用空指针】
说明:操作空指针,可能导致死机问题。
规范7:【指针内存释放后,对应指针必须置空】
说明:内存释放后置NULL,避免野指针操作。
释放了内存却继续使用它,也会导致诸多问题,常见的释放之后内存还在使用有收下几种情况:
- 程序中的对象调用关系过于复杂,实在难以搞清楚某个对象究竟是否已经释放了内存,此时应该重新设计数据结构,从根本上解决对象管理的混乱局面;
- 函数的return语句写错了,返回了指向“栈内存”的“指针”或“引用”,因为该内存在函数体结束时被自动销毁;
- 使用free释放了内存后,没有将指针置为NULL,导致产生“野指针”;
- 多个指针指向同一个内存,其中一个指针释放后,其他指针成了野指针。
错误示例:
char *p = (char *) malloc(100);
strcpy(p, “hello”);
free(p); // p所指的内存被释放,但是p所指的地址仍然不变
…
if(p != NULL) {// 没有起到防错作用
strcpy(p, “world”); // 出错
}
正确示例:
char *p = (char *) malloc(100);
strcpy(p, “hello”);
free(p); // p 所指的内存被释放,但是p 所指的地址仍然不变
p = NULL; >>>修正方案,将指针置为空
…
if (p != NULL){//起到防错作用
strcpy(p, “world”);
}
规范8:【释放结构体/数组/各类数据容器指针前,必须先释放成员指针】
说明:删除结构、其他数据窗口指针时,必须从底层向上层顺序删除,确保每个元素已经释放,释放数组时,要确保数组中的每个元素指针已经释放。
错误示例:
struct BUF_S{
int len;
char *pData;
} BUF_T;
void func(){
BUF_S *pbuf = NULL;
// 申请结构内存
// 程序处理。。。
>>>修正方案此处增加 free(pbuf->pData);
free(pbuf); //删除了pbuf ,但pbuf->pData没有删除,必然导致内存泄露
return;
}
3 变量、宏
规范9:【严禁使用未初始化的变量作为右值】
说明:对于局部变量的使用要保证使用前必须赋值,可在定义局部变量时就进行初始化,未经初始化的变量内容为随机值,如果做为右值会产生不可预知的错误,变量应该初始化为正解的缺省值。
引申:变量赋值错误、结构/类成员变量没有赋值直接使用。