一个C++ string使用问题的分析及解决
接上文日志上传服务器的场景;rsyslog出现Unit rsyslog.service is masked不可用问题解决-CSDN博客
解决了日志服务不可用问题后,做了日志上传测试,确定可以将日志上传到日志服务器后,下一步就是实打实的工程实现了。
在这个过程中又遇到一个奇怪问题,折腾了半个下午,终于解决。在这里记录一下。
还是老规矩,先说场景。有一个串口通道,可以接收一个下级设备的日志,接收端的任务就是将接收到的日志,上传到日志服务器。
按说很简单,但是实现中,发现日志总是不全,更加奇怪的是本地打印是好的。
看看博主是怎么实现的上述功能。首先,接收端有一个接口,可以每次读取n个字符,这些字符里带了下一级设备的日志,包括换行\n也是带着的。所以,本地打印就是将收到的字符一个一个打印即可。上传为了分行显示,且为了实现简单方便,用了一个queue容器,元素是string类型。想的很简单,不断接收串口的字符,每收到一个就append到一个string中,遇到\n,就将当前string放到queue中,对string执行clear,然后继续接收下一个字符。为了不影响字符接收,都是收完后,再统一从queue中取出每一行打印,然后发给日志服务器。这样一来,就不用管每行打印的长度和一次接收会有多少行的问题。如果用C来实现,边界的处理,数组或是动态内存的使用,都是少不了的,用C++的容器和string,这些都省了。
实现功能后就开始测试。结果就遇到了开头提到的丢失日志的问题。反复测试,总是会丢失个别行,为此怀疑了queue的push和front是不是拷贝传参,还研究了C++ 的string是深拷贝还是浅拷贝,并反复测试。
因为当前这个使用方式,之前在其他模块代码中也是有类似的应用的,从来没出问题,因此就感觉更加奇怪了,也开始各种怀疑,甚至怀疑是不是编译时没有clean,怀疑\n是不是会截断,怀疑string对象是不是过早释放了,为此还加入了多个临时对象来验证。总之,无论怎么修改,总是会有个别行日志丢失。
就在山穷水尽,准备用C的方式,一个字符一个字符拷贝时,突然想到,会不会是数据中有0导致string被截断了。有想法就赶快验证。实测果然是这样。
string tempStr;
tempStr.append("123");
tempStr.append(1, '\n');
tempStr.append(1, 1);
tempStr.append(1, 0);
tempStr.append("456");
上面这段代码,插入0之后打印,后面的456是显示不了的。而开头提到的问题,就是因为上报的数据里有0,所以导致日志被截断,最终使得服务器上看到的日志不全。
对0进行甄别并特殊处理后,问题解决。
通过这个例子,一方面说明软件开发是个耗时耗力的过程,哪怕是比较简单的功能,另一方面也说明基础的重要性。很多时候因为赶时间,很多接口或代码其实没有理解透彻,就在线运行了。但是话说回来,现在这个。。。谁有大把的时间慢慢一点一点研究呢?