规则1:指针变量、表示资源描述符的变量、BOOL变量声明必须赋予初值
变量声明赋予初值,可以避免由于编程人员的疏忽导致的变量未初始化引用。
示例:
1. SOCKET s = INVALID_SOCKET;
2. unsigned char *msg = NULL;
3. BOOL success = FALSE;
4. int fd = -1;
以下代码,由于变量声明未赋予初值,在最后free的时候出错。(ps:相当于释放野指针了)
1. char *message; // 错误!必须声明为 char *message = NULL;
2. ...
3. if (condition) {
4. message = (char *)malloc(len);
5. ...
6. }
7. ...
8. if (message != NULL) {
9. free(message); //如果condition未满足,会造成free未初始化的内存。
10. }
例外1: 对全局变量,静态变量,在编译阶段自动初始化为0或者等于NULL,不用在定义时强制初始化。 例如:
1. OS_SEC_BSS TICK_ENTRY_FUNC g_pfnTickTaskEntry;
2. OS_SEC_BSS volatile UINT64 g_ullSleepTime;
3. OS_SEC_BSS volatile UINT64 g_ullSleepBegin;
4. OS_SEC_BSS volatile UINT64 g_ullSleepEnd;
规则2:指向资源句柄或描述符的变量,在资源释放后立即赋予新值
资源释放后,对应的变量应该立即赋予新值,防止后续又被重新引用。如果释放语句刚好在变量作用域的最后一句,可以不进行赋值。
示例:
1. SOCKET s = INVALID_SOCKET;
2. unsigned char *msg = NULL;
3. int fd = -1;
4. ...
5. closesocket(s);
6. s = INVALID_SOCKET;
7. ...
8. free(msg);
9. msg = (unsigned char *)malloc(...); //msg变量又被赋予新值
10. ...
11. close(fd);
12. fd = -1;
13. ...
规则3:类的成员变量必须在构造函数中赋予初值
如果类中声明了变量,则必须在构造函数中对变量进行赋值。
示例:
1. class CMsg {
2. public:
3. CMsg();
4. ~CMsg();
5. protected:
6. int size;
7. unsigned char *msg;
8. };
9.
10. CMsg::CMsg()
11. {
12. size = 0;
13. msg = NULL;
14. }
规则4:严禁对指针变量进行sizeof操作
编码人员往往由于粗心,将指针当做数组进行sizeof操作,导致实际的执行结果与预期不符。 下面的代码,buffer和path分别是指针和数组,编码人员想对这2个内存进行清0操作,但由于编码人员的疏忽,第5行代码,将内存大小误写成了sizeof,与预期不符。
1. char *buffer = (char *)malloc(size);
2. char path[MAX_PATH] = {0};
3. ...
4. memset(path, 0, sizeof(path));
5. memset(buffer, 0, sizeof(buffer));
如果要判断当前的指针类型大小,请使用sizeof(char *)的方式。
建议1:尽量使用const
在变量声明前加const关键字,表示该变量不可被修改,这样就可以利用编译器进行类型检查,将代码的权限降到更低。 例如下面是不好的定义:
1. float pi = 3.14159f;
应当这样定义:
1. const float PI = 3.14159f;
建议2:全局变量的访问如果涉及多个线程,需要考虑多线程竞争条件问题
应该尽可能减少全局变量的使用,如果多个线程会访问到该全局变量,则访问过程必须加锁。 以下代码中,g_list是全局变量,对链表进行搜索操作时,在while循环语句的前后加锁。
1. ItemList *g_list = NULL;
2.
3. ItemList *SearchList(const char *name)
4. {
5. Lock();
6.
7. ItemList *p = g_list;
8.
9. while (p != NULL) {
10. if (strcmp(p->name, name) == 0) {
11. break;
12. }
13. p = p->next;
14. }
15.
16. UnLock();
17.
18. return p;
19. }
性能敏感的代码,请考虑采用原子操作或者无锁算法。
建议3:同一个函数内,局部变量所占用的空间不要过大
程序在运行期间,函数内的局部变量保存在栈中,栈的大小是有限的。如果申请过大的静态数组,可能导致出现运行出错。 建议在申请静态数组的时候,大小不超过0x1000。 下面的代码,buff申请过大,导致栈空间不够,程序发生stackoverflow异常。
1. #define MAX_BUFF 0x1000000
2. int Foo()
3. {
4. char buff[MAX_BUFF] = {0};
5. ...
6. }
参考:gitcode社区-开源文档-菊厂C&C++安全编程规范