编码注意事项

# 内存泄漏

1、对动态内存的使用保持敬畏,一旦malloc过,free要谨记在心。

尤其是对于多重提前return的函数,如:

 1 void func(void)
 2 {
 3     char *ptr = malloc(100);
 4     ...
 5     if (condition1) {
 6         ... // !!! 记得free
 7         return;
 8     }
 9     
10     ...
11     if (condition1) {
12         ... // !!! 记得free
13         return;
14     }
15     
16     // !!! 记得free
17 }

2、减少动态内存的嵌套使用,如:

 1 struct item_ctx {
 2     char *ctx; // dynamic alloc
 3 }
 4 
 5 struct item {
 6     int item_desc;
 7     struct item_ctx *ctx; // dynamic alloc
 8 }
 9 
10 struct queue {
11     int size;
12     struct item *data; // dynamic alloc
13 }

这里层层嵌套,使用完很容易漏掉某个地方的内存释放。

3、釜底抽薪之策:尽量不用动态内存。

比如,如果一项业务最大使用内存是知道的,就可以使用栈内存。如此,既避免了内存泄漏,又有效率方面的提升。

4、智能指针

# 死锁

死锁的避免措施,在思想上和预防内存泄漏是一样的。重复一遍就是:

1、lock/unlock成对出现

2、避免锁的嵌套

3、设计阶段,尽量避免锁的使用

4、智能锁

# for/while语句导致死循环

这是一个比较容易忽视、一旦出现(尤其大型软件)很难排查的问题,一个简单示例:

1 uint32_t g_counter;
2 
3 while (g_counter > 0) {
4     g_counter --;
5     ...
6 }

如果 g_counter 减到0的瞬间,又被外部某段代码减了一次,bug就这么发生了。

# system()系统调用

在使用system/popen执行系统命令的时候,注意参数可能带空格的情况,如:

1 system("wpa_passphrase ssid passwd_1234");

上述命令根据用户的WiFi热点"ssid"对明文密码"passwd_1234"进行加密,如果"ssid"带空格的话就悲剧了。

解决措施:在构建命令的时候,记得用引号("")圈起来。

# errno的误用

一种常见的 errno 错误使用示例

if (somecall() == -1) {
   printf("somecall() failed
");
   if (errno == ...) { ... }
}

errno 是一个全局变量,当 if (errno == ...) 的时候,errno 的值可能已经被其他代码修改掉了。

正确的做法是,在 somecall() 调用异常时,尽快保存 errno 的值:

if (somecall() == -1) {
   int errbk = errno;
   printf("somecall() failed
");
   if (errbk == ...) { ... }
}

# 宏定义使用

1、宏定义时记得用括号()引起来。

2、编码过程中如果修改了宏,一定要 rebuild (make clean;make)你的工程。

 # 使用变量前一定要初始化

示例:

char buffer[32];

// 错误做法!!!
strncpy(buffer, src, sizeof(buffer) - 1);

// 正确做法
memset(buffer, 0, sizeof(buffer));
strncpy(buffer, src, sizeof(buffer) - 1);

 # 字节对齐

涉及结构体成员大小的时候,注意字节对齐问题。如:

struct msgq_data {
	pid_t pid;
	size_t len;
}

在 64 位系统上,pid_t 类型占 4 字节大小,size_t 类型占 8 字节大小,编译器按照 8 字节对齐,所以 pid 成员也是 8 字节大小。

待续。。。

原文地址:https://www.cnblogs.com/rockyching2009/p/12917317.html