前言
之前大部分代码都是写好的,只是偶尔修改一下bug,添加新需求。只要代码不报错,没有语法错误,就能入库,现在新公司提交代码后,CTO也就是技术总监(现在软件部有一个BSP负责驱动和编译,两个嵌入式开发负责写代码,还有一个CTO负责整个团队)会仔细的review代码,并给出修改意见,这才是review的作用,原公司的review感觉只是个形式。
这第一次代码优化就是根据CTO的意见进行的,非常感谢他,如果没有人提出意见我可能一直不会有新的提升与收获。
下面就以此记录修改的地方
宏定义
现状
由于项目中的类很多,有很多类都使用了同一个文件、程序、字符串、字符长度等,在使用时为了图方便都写到了对应的cpp文件上方,造成了有很多意义重复的宏定义
优化
创建一个公有的头文件,里面只放宏定义,有两个及以上的类要用到的宏定义都放到这个头文件中,需要使用时包含这个头文件即可
枚举
现状
代码中有很多绝对数字,让人费解,如下,是判断当前网络设置的代码,对于数字让其他人很难理解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| if (mode == 11) { } else if (mode == 18) { } else if (mode == 19) { } else { }
|
优化
使用枚举让代码更加便于阅读,更方便维护:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| enum MS_NETWORK_MODE { MODE_LTE_ONLY=11, MODE_LTE_5GNR=18, MODE_5GNR_SA=19, MODE_AUTO=40 };
if (mode == MODE_LTE_ONLY) { } else if (mode == MODE_LTE_5GNR) { } else if (mode == MODE_5GNR_SA) { } else { }
|
system()
在代码中经常使用system()完成一些Linux的操作,如复制,移动,删除等。我一直认为这是很正常的,直到CTO给我说了system()的调用过成我才知道为什么要优化他。
system()的调用过程为:
- 当参数为NULL时直接返回,不为NULL时fork()一个子进程
- 父进程等待,子进程使用execl 启动shell命令
- shell去执行我们下发的命令
- 执行完成,父进程等待结束,返回结果
第三步是多余的操作,相当于shell又fork了一个进程去执行我们的命令(不知道这样理解是否正确),完全可以跳过这步,于是有了自己实现的do_system(),也就是上篇服务管理系统的核心函数,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
| int do_system(unsigned char wait, int *svc_pid, const char *exec_file, list<string> arg_list) { pid_t pid; int status; sigset_t chldmask, savemask; list<string>::iterator list_iterator;
if (exec_file == NULL) { return (-1); }
sigemptyset(&chldmask); sigaddset(&chldmask, SIGCHLD); if (sigprocmask(SIG_BLOCK, &chldmask, &savemask)) { return (-2); }
pid = fork(); if (pid < 0) { sigprocmask(SIG_SETMASK, &savemask, NULL); return (-3); } else if (pid == 0) { int n = 0; char **argv; int argc = 0; char **p; n = arg_list.size(); p = argv = (char **)malloc((n + 1) * sizeof(char *)); p[argc] = (char *)exec_file; if (n > 0) { for (list_iterator = arg_list.begin(); list_iterator != arg_list.end(); list_iterator++) { p[++argc] = (char*)(*list_iterator).c_str(); ALOGI("param:%s",p[argc]); } }
p[++argc] = NULL;
n = execvp(exec_file, argv); free(argv); exit(n); } else { if (svc_pid) { *svc_pid = pid; }
if (wait) { while (waitpid(pid, &status, 0) < 0) { if (errno != EINTR) { sigprocmask(SIG_SETMASK, &savemask, NULL); return (-1); } } } else { sigprocmask(SIG_SETMASK, &savemask, NULL); return (0); } }
sigprocmask(SIG_SETMASK, &savemask, NULL); return WEXITSTATUS(status); }
|
其中参数列表list可以换成C语言的多参数,以便在C中使用,关于多参数我后面也会单独记录
多命令连续使用system()
现状
在代码中有连续的system()调用,即使换成我们自己实现的system()也会fork很多进程,例如备份文件的代码,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| system("rm -f /usr/www/Backup.zip"); system("mkdir /usr/www/backup"); system("mkdir /usr/www/backup/etc"); system("mkdir /usr/www/backup/data"); system("mkdir /usr/www/backup/cgi"); system("cp -p /data/cgi/admin_config /usr/www/backup/cgi/admin_config");
system("cp -p /etc/timezone /usr/www/backup/timezone");
system("tar -zcf /usr/www/Backup.zip /usr/www/backup/*"); system("rm -rf /usr/www/backup");
|
优化
将命令全部写到文件中,然后调用shell命令运行文件,避免多次调用system(),简单实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #define SHELL_FILE /tmp/cmd_shell.sh
FILE *fp; char line[128] = {0};
if ((fp = fopen(SHELL_FILE, "w")) != NULL) { sprintf(line, "rm -f /usr/www/Backup.zip\n"); fwrite(line, sizeof(char), strlen(line), fp); sprintf(line, "mkdir /usr/www/backup\n"); fwrite(line, sizeof(char), strlen(line), fp); sprintf(line, "mkdir /usr/www/backup/etc\n"); fwrite(line, sizeof(char), strlen(line), fp); sprintf(line, "mkdir /usr/www/backup/data\n");
fflush(fp); fclose(fp); } system("sh "SHELL_FILE);
|
fprintf()
现状
在写文件时,不止上面那种执行命令的情况,包括修改配置文件需要写很多行,使用sprintf(),不仅要多调用一次fwrite,还要担心定义的数组line是否会越界,所以可以直接使用fprintf()
优化
fprintf()我之前也是没有用过的,也是看到建议后才知道,真惭愧,优化后的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #define SHELL_FILE /tmp/cmd_shell.sh
FILE *fp; if ((fp = fopen(SHELL_FILE, "w")) != NULL) { fprintf(fp, "rm -f /usr/www/Backup.zip\n"); fprintf(fp, "mkdir /usr/www/backup\n"); fprintf(fp, "mkdir /usr/www/backup/etc\n"); fprintf(fp, "mkdir /usr/www/backup/data\n");
fflush(fp); fclose(fp); } system("sh "SHELL_FILE);
|
总结
第一次优化的点就是这些了,后续有继续优化会及时更新新的文章.
我买一本 《Effective Modem C++》,抽空阅读后也会将收获(笔记)记录下来