为什么 C/C++ 语言会有未定义行为?
37 个回答
为了性能优化。
数组问题其他答案都说了,简单来说就是检查的开销甚至可能大于操作本身的开销。
我这边另一个举例就是大小写转换,char类型大小写转换只需要把第六位做位运算就行了,速度非常快,你可以使用avx来向量化,一个G的字符串单线程只需要0.1秒就转完。
但是他的代价就是你输入的东西不是字母A-Za-z的话就会有UB(实际上也不算UB,就是不正常的行为)。
那么我能不能先检查是不是字母,是的话位运算不是的话不做任何事呢?(嗯,其实STL的方法就是这么做的)
恭喜你,当你做这个检查以后,你很难把单线程1G字符串的大小写转换时间压进0.5s。而且用于涉及到多个条件判断(别忘了大Z和小a之间还特么有几个字符,需要4次大小比较),你需要使用AVX掩码操作,代码极其麻烦的同时,性能大幅下降。你要多倒腾好几个寄存器,多出3-6倍(取决于编译器优化)的AVX重指令。而不检查的方法只需要倒腾两个ZMM(其中一个是常量)、一个地址寄存器和一个计数变量。
同时印象中只有AVX512实现了复杂的掩码控制,在AVX2的时代,更麻烦。
在对性能极为敏感的应用(尤其是高性能计算行业)中,我们允许一定程度上的UB,允许一定程度上的不能正确handle异常,通过对用户的输入做出规范要求来获得性能提升。比如在我的那个应用中,如果用户得到了UB,我会拒绝他的bug修复申请并询问:为什么你的基因组测序序列里会有非字母?
当然我知道这种思路是有违互联网行业开发规范的,但是很不幸,高性能计算和互联网是两个行业,我们的客户是讲道理的,不会向你的程序中喂进去各种奇奇怪怪的东西,他们会欣然同意为了性能的考虑增加对输入的合理限制(比如说测序序列中本来就完全不应该出现非字母),他们只有一个要求:
慢是原罪。