当前位置:C++技术网 > 资讯 > 诡异的指针传参,怎么死的都不知道

诡异的指针传参,怎么死的都不知道

更新时间:2017-05-12 00:49:08浏览次数:1+次

    要说起指针,爱之又恨之。不过恨的时候,真是恨得咬牙切齿。特别是在大项目里面,指针满天飞,会让你想死!!一点都不假。
    还记得一年前维护的一个项目,软件结构是分层式的结构,所以一个参数会传遍很多层。然而为了传参的效率,然后不断的传递指针。最后就是指针满天飞,然后就是,各种Bug变着花样出来,而且还不容易重现,调试起来真的要吐血。
    今天又遇见了指针的诡异问题。先来看看代码:
CMD hcmd = { 0 };
rate_query(pile_id,&hcmd);
dxLog_Base::WriteLineStr("费率查询完毕");
    费率查询函数定义如下:
void rate_query(string pile_id,CMD *phcmd)
{
 string rate_str = GetFeeRate(1);
 CMD hcmd = GetRateStruct(rate_str);
 dxLog_Base::WriteLineStr("返回");
 dxLog_Base::WriteLineByte((const char*)&hcmd,sizeof(CMD));

 memcpy(phcmd,&hcmd,sizeof(CMD));
 dxLog_Base::WriteLineStr("复制给结构体");
 dxLog_Base::WriteLineByte((const char*)phcmd,sizeof(CMD));
 return hcmd;
}
    为了让你更好的看清楚代码的意思,我简化了实际代码。rate_query是查询费率的函数,CMD是一个结构体,rate_query通过第二个参数将结果传回,也就是通过指针传参。因为函数内部生成的结构体是自动变量,随着函数执行完毕,自动变量会销毁。所以我们这里就用了memcpy,将变量值复制给第二个参数的指针所指向的内存。也就是说,我们这里是将数据复制出去了。函数内的变量销毁了,也不影响。
    这个看似很OK的代码,运行之后,很诡异的就崩溃了。我使用dxLog_Base类的函数来打印日志。可以观察到,memcpy前后的日志都正常打印。而rate_query函数后面的“费率查询完毕”没有打印,然后程序崩溃了。这可以表明,是rate_query返回时崩溃的。
    你看出来是什么问题了吗?关键是,这个是在一个客户端连接上时才会发生,其他的客户端连上了不会出问题。让人还是很费解的。为了解决问题,就将传参方式换成了函数返回值方式。然后就可以了。
    因为这个是多线程的程序,而且是Linux网络服务器程序,调试起来还是很麻烦的。尽管通过传值方式确实解决了问题,但是出现这个问题的真正原因还没有找到。
    这里不是讲解如何去找到这个问题的,而是分享一个经验。
    我们知道,C/C++问题,最头疼的就是指针问题,很多时候还很诡异。特别是在一个大项目里,因为指针使用不规范,导致到处都有指针,而且管理不善,还到处传递指针。当指针传递的层次多了之后,看似正常,很多时候都是埋下了巨大的坑。
    我们先不用纠结这些指针问题到底是怎么回事,为了能够尽量避免这些指针问题,我们最好的办法就是预防。预防的方法就是,规范指针使用。特别是在大项目里,使用指针一定要谨慎,否则今后坑的人还是自己。
    如果一般的传参,能够用传值就不要用指针传递。就效率来讲,我想你不会为了这点效率,不断的加班调试找错误吧。当然更确切的说,是在大项目里面,更应该如此。减少Bug出现的机会,是提高软件质量的一个方法。特别是有层层传递参数的场景,特别容易出现问题。还有就是多线程的场景,传参也要注意了。在多层次的传递参数的时候,尽可能的确保每一层的传参是可靠的,不要将一个不可靠的参数和未经过验证的参数直接往下传。一旦出了问题,跨层的参数调试起来是非常麻烦的。同时,也因为跨层的传参容易出错,特别是指针参数。
    总结一下,对于指针的使用,注意以下两点:
1.能够用传值方式传参,就不要用传指针方式传参。
2.多层次调用、多线程、复杂项目中,尽量选择传值方式传参,切忌在多层次函数调用中直接传递指针。