代理偏见
近期在某运行环境上看到一条提示信息,说出现运行错误时,可能是由于调用了非标准库函数引起的。
我对此非常疑惑:“非标准库函数”这个概念太大了,除了编程语言自带的标准库以外,任何一个函数都是非标准库函数——Linux操作系统API也是,第三方开源库函数也是,同一个项目里的其他模块函数也是,甚至我自己代码里定义一个函数也是“非标准库函数”。
调用非标准库函数会不会导致运行错误?当然有可能,调用任何一个函数都可能导致运行错误——即使是标准库。C语言标准库中有一大堆接收内存地址参数的函数,随便挑一个传个错误地址进去,想跑出错误轻而易举。但问题是,运行错误和是不是“非标准库函数”这个特征有一丁点儿联系吗?如果没有联系,为什么要强调这个特征呢?
我向人询问这个提示的来源,得到了这么一个故事:
几年前,很多人在这个环境上写C代码时,习惯性的使用strdup这个函数,发现只要用了strdup就会产生程序运行时的signal错误,大家觉得是strdup函数有问题。由于编译C代码时指定了C11标准,而strdup不属于C11标准库函数,于是就写出了这条提示让大家不要调用非标准库函数。
我好奇strdup为什么会出问题,就去环境上试了几下,再在网上一搜,得知是这么个原因:
https://stackoverflow.com/questions/8359966/strdup-returning-address-out-of-bounds
当指定-std=c11参数时,gcc认为用户想要尽可能遵循C11标准,就在string.h头文件中屏蔽了strdup函数声明。这时用户写的代码中调用的strdup是个没有被声明的函数。C语言允许调用未声明的函数,但会自动把函数返回值声明为int类型。于是,本来返回char*类型的strdup函数,在编译时被当做返回int类型。运行时strdup返回的指针被转换为int导致值被截断,后续访问这个指针产生未定义行为。
这个问题的本质原因来自C语言的陷阱——调用未声明的函数也能编译通过,而且函数返回值自动声明为int。别说strdup,任何一个返回指针的函数未声明就调用都会出一样的问题。对于有经验的C程序员来说,只要关注一下编译告警就能发现这种问题。
gcc在指定-std=c11参数时,屏蔽掉strdup声明这个做法对不对呢?——在Linux中,string.h头文件包含有strdup,但是在C11语言标准中,string.h头文件又不包含strdup,这使得编译器必须做出选择。在默认配置下,gcc选择包含strdup的声明,但如果这时用户代码中自定义了strdup,会和已有定义产生冲突。然而严格按C11标准,这种自定义strdup的代码是应该正常编译运行的。所以,为了遵从C11标准,gcc选择了在指定-std=c11参数时不包含strdup的声明(但也可以通过定义特定的宏来打开)。
再回头看,开始时那条提示信息的产生过程是这样的:
代码运行出错了 -> 定位发现只要用了strdup就出错 -> 运行环境上strdup有问题(第一次“代理”) -> 非标准库函数有风险(第二次“代理”) -> 写个提示不要用非标准库函数
上面的流程中,两次不当的代理导致了最后这个奇怪的结论。第一次代理:“特定编译环境下用了strdup的代码出问题”代理为“strdup函数有问题”;第二次代理:"strdup函数有问题”代理为“非标准库函数有风险”。
我把这种不当的代理叫做“代理偏见”。代理偏见在各种讨论中广泛的存在,最著名的是网上的“地图炮”:“新闻中老有某个省的人偷井盖”——代理为“某个省的人全都偷井盖”。
代理偏见能这么流行,我估计一个重要的原因是它省脑容量。通常一个真实的因果关系要包含很多成立的前提,但这么多细节既不利于记忆也不利于传播,而代理为一个简单粗暴的结论,脑容量就省下很多了。“在使用了-std=c11编译参数时,gcc屏蔽string.h中strdup函数声明导致用户代码中strdup被声明为返回int使得指针被截断”这多难记啊,代理一下,变成“使用非标准库函数会导致执行出错”这就好记多了。至于对不对,那先不管,抛开事实不谈,至少后面那个结论它好记好传播。
有意思的是,现在大量的人表面上似乎对于代理偏见很警惕,知道它不对,有时还能指出这种问题,网络论坛也都在强调不要地图炮。但同时,在和很多人讨论问题的时候又经常能见到代理偏见大行其道。
说几个我经常听到的结论吧,大家看是不是很常见:
圈复杂度低的代码是cleancode,圈复杂度高的代码不是好代码;
用了C安全函数的代码安全,用了非安全函数的代码不安全;
C++代码中函数传参时传引用比传值性能高;
前置自增操作符比后置自增操作符的性能高;
同样功能,用多线程实现比用单线程实现性能高;
在单核CPU上运行时,并发读写基本数据类型不用加锁;
……
如果以上这些结论中有任何一个是你深信不疑的,恭喜你,你就是代理偏见大军中的一员。
- 点赞
- 收藏
- 关注作者
评论(0)