前言
其实发生段错误的情况有很多:
其实在项目的开发中最有可能的错误就是①和②,考虑到本项目数组用的比较少,所以主要是考虑错误①指针的误用。
有时候错误就是那么离谱,声音也算是一种设备?????
出错原因:对语音模块发出开机的指令就会出现段错误,然后各种错误
有时候又没有段错误
找bug的过程:
第一次找:
怀疑是多线程的问题,把线程一个一个注释掉,发现第四个线程注释掉就不会出现“Segmentation fault”
解决思路:
对比其他三个线程的结构,有没有什么不一样。
对比下来发现,功能其实差的比较大,receive线程的主要目的是接收处理数据,而其他3个都是直接添加设备,果断转战下一个解决思路。
ps:这里补充VsCode的一个对比工具“Partial Diff”插件
差异对比犀利手册:使用 Partial Diff 插件在 VSCode 中比较代码差异_vscode提交代码对比插件-CSDN博客
还补充了 gdb调试 的基本步骤
---------------------------------------------------------------------------------------------------------------------------------
第二次找:
在receive线程里面一句一句的排查注释,最终锁定一段代码、一句话
解决思路:
其实仔细一想,也不是这里的问题,这里只是初始化,情况内存,不是核心问题(因为此时的核心问题没有找,所以根本发现不了,只能挨着继续往下寻找)
---------------------------------------------------------------------------------------------------------------------------------
第三次找:
进一步排查,发现是该函数的memset的下面一句发生了错误,同样也发生了错误
解决思路:
排查到这句话,现在想起来其实是可以说明 cur_gdev->gpio_status 的状态是有问题的,只是当时不清楚,排查不到这里去。当时的解决思路完全是去纠结这里的语法去了
第一次改 :strcpy(change_status, cur_gdev->gpio_status == LOW ? "Open" : "Close");
修改的原因是:考虑字符串不能直接赋值。
但是不幸的是仍然是报错
所以又试了试不用三目运算符来写一下试试???
发现还是不行还是段错误。
继续考虑,会不会是指针没有分配到地址??
还是报错!
此时又回过头来考虑语法的问题
想了想 change_status 是一个指针,而 cur_gdev->gpio_status 是一个int类型,这两个能直接比较吗?
而且能够把字符串赋值给int类型的变量吗?现在想想都觉得当时写的很好笑
这个时候就应该考虑让 gpio_status 与一个数字作比较来判断高低电平
if (gpio_status == 0)
以及用 strcpy() 来对字符串赋值
但是仍然是报错!!!!
此时的报错原因 就是,语音模块的开机,“你好 小美” 就会出现段错误
没办法继续找吧,但是此时可以确定,该程序能不能跑到这里去
-------------------------------------------------------------------------------------------------------------------------------
第四次找:
还是把这段注释掉就不会崩,此时还是没有找到报错的核心问题
---------------------------------------------------------------------------------------------------------------------------------
第五次找:
第四次找的每一步都加上打印,最后确定查询到哪里停止
解决思路:
推荐方法 : printf("running %d \n",__LINE__);
如果程序崩了的话就看看running停在了哪里 哪里就是问题所在
现在可以基本上确定问题所在 “change_status”的数据没有,所以造成了错误,逐渐向真相靠近
并且把这一步注释掉,没有任何意义,根本copy不了,gpio_status 这玩意又不是指针,所以留着也没什么意义
这一句的作用就相当于上面那一句了
当删了这句话之后,程序往前跑了一步
此时说明 cur_gdev->gpio_status 的状态根本就是一个空白的数据!!!拿不到数据才会段错误(这个时候才算是真正的发现了出现段错的核心所在了)
---------------------------------------------------------------------------------------------------------------------------------
第六次找:
跟着往上发现是cur_gdev 这个指针有问题
解决思路:
打印该指针的 io状态 、以及 地址(先打印地址,没有地址的话哪来的io状态???)
发现该指针的地址为空,这才是发生段错误的真相!根本就拿不到当前指针的地址,剩下的数据也不可能拿到
所以接下来的操作就是看看这个变量会经历什么过程,为什么会没有空间??
此时的核心问题已经转移到该函数 find_gdevice_by_key 上面
因为目前的状态就是该函数根本拿不到数据,打印出来的 cur_dgev 的地址就是一个空
此时就要进一步探讨这个函数的实现逻辑是怎么样的,对比了什么指令,对比指令,传入参数这些是否正确????
-------------------------------------------------------------------------------------------------------------------------------
第七次找:
打印 find_gdevice_by_key 的比对结果是怎么样的
发现是正常的结果
此时就要使用 gdb 调试,找到这个函数 打断点
多文件多函数打断点的方法 break myFile.c:myFunction
得把其他的线程注释掉来调试
解决思路:
此时考虑 find_gdevice_by_key 的主要功能,在这个函数进行打印调试
发现也是正确的
除此之外还进行了其他的调试
没办法这些也不是最主要的点
第八次找:
考虑一件事(最原始的问题,最初的问题),为什么是开机就会发生段错误???
打开客厅灯不会发生段错误,为什么就开机会发生段错误???
解决思路:
这时候灵光一现!“你说声音会不会是一种设备?作为指令传入到被控设备链表之中”
此时添加 voive_gfevice 文件
奇迹的出现!真的没有报错了
至此,问题得到了解决,就是没有把声音当作一个设备,进行传入到当前的设备链表之中,所以造成了只有开机的时候才会发生段错误,因为没有添加开机设备的指令的时候,此时开机就没有指令传到被控链表之中,而find_gdevice_by_key 这个函数只会到当前已加入的设备链表中比对发送的指令,自然也就比对不到声音发过来的0x40这样一个指令,所以就会报错!
========================================================================
更新于第二天:
问题的核心其实还是cur_gdevice为空,但是还是要补充
其实上面的解决的bug只能够解决一时,真正想让项目运行起来的是解决办法是