一、简单开个头
: 最近做了一个LoRa网关的项目接近尾声了,从项目开发、测试到项目结项这个过程心情是此起彼伏啊~ 把一些从技术、设计、项目管理角度给大家分享一些我在项目开发过程中遇到的问题,一些常见的坑,告诉给大家,希望看过此篇博客的小伙伴以后避免入坑~
二、技术篇
C语言:
-
指针
(1) : 指针变量一定要赋初值 ,定义变量一定要赋初值。例如:char *node_buf = NULL; //指针型
char g_flag = 0; //char型
int malloc_size = 0; //int型
struct host_data mqtt_send_msg = {
.option = HOST_OPTION_SOCKET, //枚举类型
.client_fd = 0,
.data_size = 0,
.data_buff = {0}
}; //结构体类型
char uri[80] = {0}; //数组
mqtt_para_t mqtt_para = {0}; //结构体数组
(注意:不赋初值会出现野指针、参数错误等现象)(2):使用指针前一定要判空加异常处理。例如:
if (node_info_ptr == RT_NULL) { LOG_STD(LOG_ERR, "node_info", "node_info malloc error!\r\n"); rt_free(node_info_ptr); return 0; } if (gwinfor_buf != NULL) { strcpy(buff,gwinfor_buf); len = rt_strlen(gwinfor_buf); rt_free(gwinfor_buf); return len; } else { rt_kprintf("gwinfor_buf is NULL \n"); return 0; }
-
变量类型的范围
(1):选用什么变量类型,一定先考虑改变量类型的最大值与最小值,很重要,很容易被忽略。
-
存在危险的库函数,要谨慎使用。
(1):字符串拷贝函数 :strcpy(char* dest, const char *src)。
: 如 果 ∗ s r c 所 指 向 的 字 符 数 大 于 ∗ d e s t 所 指 向 缓 冲 区 的 最 大 长 度 , 则 会 导 致 内 存 溢 出 \color{red}{如果 *src 所指向的字符数大于 *dest所指向缓冲区的最大长度,则会导致内存溢出} 如果∗src所指向的字符数大于∗dest所指向缓冲区的最大长度,则会导致内存溢出
(2):字符串格式化函数:sprintf(char *string, char *format [,argument,…])。
: 如 果 ∗ f o r m a t 所 指 向 的 字 符 数 大 于 ∗ s t r i n g 所 指 向 缓 冲 区 的 最 大 长 度 , 则 会 导 致 内 存 溢 出 \color{red}{如果 *format 所指向的字符数大于 *string所指向缓冲区的最大长度,则会导致内存溢出} 如果∗format所指向的字符数大于∗string所指向缓冲区的最大长度,则会导致内存溢出
而且该函数是有返回值的:如果成功,则返回写入的字总数, 不 包 括 字 符 串 追 加 在 字 符 串 末 尾 的 空 字 符 , 如 果 失 败 , 则 返 回 一 个 负 数 \color{red}{不包括字符串追加在字符串末尾的空字符,如果失败,则返回一个负数} 不包括字符串追加在字符串末尾的空字符,如果失败,则返回一个负数。
(3):内存拷贝函数:memcpy(void *destin, void *source, unsigned n)。
: 拷 贝 前 , 尽 量 使 用 m e m s e t 先 将 内 存 初 始 化 清 空 一 下 ! \color{red}{拷贝前,尽量使用memset先将内存初始化清空一下!} 拷贝前,尽量使用memset先将内存初始化清空一下!
(4):字符串长度统计函数:strlen(char *s)。
:它从内存的某个位置(可以是字符串开头,中间某个位置,甚至是某个不确定的内存区域)开始扫描,直到碰到第一个字符串结束符’\0’为止,然后返回计数器值(长度不包含’\0’)。
我 们 经 常 把 s t r l e n ( ) 直 接 作 为 入 参 使 用 , 如 果 我 们 不 考 虑 s t r l e n 会 返 回 的 最 大 值 , 就 可 能 会 出 现 各 种 意 向 不 到 的 错 误 ! \color{red}{我们经常把strlen()直接作为入参使用,如果我们不考虑strlen会返回的最大值,就可能会出现各种意向不到的错误!} 我们经常把strlen()直接作为入参使用,如果我们不考虑strlen会返回的最大值,就可能会出现各种意向不到的错误! -
建议使用这些安全的库函数。
(1):将指定长度的字符串拷贝函数:char *strncpy(char *destinin, char *source, int maxlen);
s o u r c e 和 d e s t i n i n 所 指 内 存 区 域 不 可 以 重 叠 且 d e s t i n i n 必 须 有 足 够 的 空 间 来 容 纳 s o u r c e 的 字 符 长 度 + 结 束 符 \color{red}{source和destinin所指内存区域不可以重叠且destinin必须有足够的空间来容纳source的字符长度+结束符} source和destinin所指内存区域不可以重叠且destinin必须有足够的空间来容纳source的字符长度+结束符
(2):指定大小的格式化函数:int snprintf(char * dest_str,size_t size,const char * format,…);
(3):带有最大长度限制的字符串长度统计函数:strnlen(const char *, size_t);
三、设计篇
: 这里我们主要说一下嵌入式软件架构设计,现在多大数主要还是根据应用需求开发,都是在一些移植的物联网操作系统比如:RT-thread、FREERTOS等上写产品应用app。前期的产品需求是很重要的,系统工程师会根据前端给到的产品需求开始规划整个应用逻辑。
(1):一定要先考虑好要开几个服务(线程),线程栈大小,优先级。
(2):参数区的划分,哪些是需要存到flash、RAM,文件系统的大小,BOOT的大小限制。
(3):线程之间的通信与互斥:消息队列(长度、大小…)、上锁、解锁。
(4):一些应用的异常处理逻辑,比如:socket的连接超时、参数获取失败、网络不通…。
(5):参数的范围:[min~max],开区间还是闭区间,最大限制多少,支不支持中文,特殊字符,等…
这 些 一 定 要 在 详 细 设 计 中 体 现 出 来 , 相 应 的 服 务 流 程 图 , 伪 代 码 都 要 给 出 来 ! \color{red}{这些一定要在详细设计中体现出来,相应的服务流程图,伪代码都要给出来!} 这些一定要在详细设计中体现出来,相应的服务流程图,伪代码都要给出来!
:如果详细设计没有做好,就为了项目进度去开发,那么之后带来就是无限的 “返工”和 “需求变更”最后的结果就是连一轮测试都很难推进~
三、管理篇
:一个项目的核心就是项目经理和研发代表,根据IPD管理流程,项目一旦开始研发代表是没有话语权的,所有的项目进度掌控都在项目经理手上,具体管理方向细节我们不聊,我们就说一个项目成立后我我们所有的工作人员初期都是信心百倍,力量实足,主要力量就是我们的研发人员,研发代表就是领头羊,在开发中遇到一些问题如果研发代表都不敢拍板,最后连开发人员都没信心做下去了,项目经理如果不实时关注研发进度和遇到的问题不及时的去协调资源,项目延期是必定的,最后一个项目拖到最后,大家的士气早已耗尽,都开始糊弄。
四、总结
:笔者参加的这个项目从6月份干到12月,技术预研4~5月就几乎开始,哎,直到现在测试到四轮还没过,哎,属实是不想再喷了,干一个好项目,下来自己身心舒畅,干一个拖拉的项目,你会被折磨的学到更多的东西,不管什么的经历都是一种成长,大家一起共勉吧!