指针容易,优化复杂

2020-09-15 21:46:39

就在最近,拉尔夫·荣格在2018年发表了一篇题为“指针很复杂”的帖子。中心论点是,大多数C(和汇编语言)程序员认为指针只是一个恰好是机器地址的整数的模型是错误的,事实上,作者直截了当地指出:指针绝对不是整数。这是一个强有力的论断。我喜欢强有力的声明,因为它们使讨论成为可能。因此,让我们以同样的方式回应:认为指针绝对不是整数的说法是错误的。作者用来说明指针绝对不是整数的例子如下:int test(){auto x=new int[8];auto y=new int[8];y[0]=42;int i=/*一些无副作用的计算*/;auto x_ptr=&;x[i];*x_ptr=23;return y[0];}。

这就是推理的关键所在:能够将y[0]的最终读取优化为仅返回42将是有益的。此优化的理由是,写入指向x的x_ptr不能更改y。

因此,指针是硬指针,而不是整数,因为它们与这个优化冲突,而这个优化对";是有益的。我觉得这很有趣:优化显然比简单而明显的指针模型更重要,甚至不需要解释为一种可能的权衡,更不用说为什么权衡会被解决成有利于拥有的优化。我更喜欢简单明了的指针模型。非常喜欢。这种将优化器的关注点放在程序员的前面的方式并不是独一无二的,如果你查看克里斯·拉特纳的“每个C程序员都应该知道什么是未定义的行为”,你会注意到短语“启用……”经常出现。优化";。这几乎是有史以来唯一给出的理由。我称这种现在业界占主导地位的编程风格为Compiler Optimizer Creator Oriented Programming(COCOP)。它在每个编译器编写者应该知道的程序员或基于未定义的行为损害性能的“优化”(Pdf)中受到了彻底的批评。当然,有些机器的指针不是整数,最突出的是8086/80286 16位分段模式,其中(远)指针由一个段和一个偏移量组成。在8086机上,段简单地左移4位并加到偏移量上,在80286上,段可以位于存储器的任何位置,也可以不驻留在存储器中,实现分段虚拟存储器。AFAIK,这些模式是iAPX432对象内存模型的简化变体。在这种情况下,值得注意的是iAPX432及其内存模型严重失败,业界积极而愉快地从x86分段模型转移到所谓的扁平地址空间,这种地址空间在其他架构上很常见,最终也被英特尔与386一起采用。平面地址空间的显著特征是指针是整数,事实上这种等价性对CPU体系结构也有相当大的影响,因为地址空间几乎普遍与CPU的整数大小捆绑在一起。因此,虽然68K标榜为16位CPU(或16/32),但它的寄存器实际上是32位的,IIRC的地址ALU完全是32位的,所以如果你想做一些32位的算术运算,LEA(加载有效地址)指令是你的朋友。8086采用分段架构的原因是它是一台真正的16位机器,有16位寄存器,但英特尔想要20位地址空间。因此,不仅过去和现在都存在指针和整数的等价性,而且一旦我们再次达到这种状态,我们就会积极寻求并愉快地接受这种状态。放弃它进行美好的优化似乎充其量是有争议的,但至少这是应该讨论/辩论的事情,而不是简单地假设它会消失。