首页 > 解决方案 > 为什么不建议在 C 中使用指针进行数组访问

问题描述

我正在学习 C 编程,并且在线浏览了本教程,其中指出您应该始终尽可能地使用 [] 运算符而不是指针运算。

https://www.cs.swarthmore.edu/~newhall/unixhelp/C_arrays.html#dynamic

你可以使用指针算术(但一般不要)

考虑 C 中的以下代码

int    *p_array;
p_array = (int *)malloc(sizeof(int)*50);

for(i=0; i < 50; i++) {
  p_array[i] = 0;
}

使用像下面的代码这样的指针算术有什么区别(以及为什么不推荐)

int    *p_array;
p_array = (int *)malloc(sizeof(int)*50);      // allocate 50 ints

int *dptr = p_array;

for(i=0; i < 50; i++) {
  *dptr = 0;
  dptr++;
}

在哪些情况下使用指针算法会导致软件出现问题?是不好的做法还是没有经验的工程师可以不注意?

标签: carrayspointerspointer-arithmetic

解决方案


由于似乎对此感到困惑:

在过去,我们有 16 位 CPU,例如 8088、268 等。要制定地址,您必须加载段寄存器(16 位寄存器)和地址寄存器。如果访问数组,您可以将数组基址加载到段寄存器中,地址寄存器将是索引。这些平台的 C 编译器确实存在,但指针运算涉及检查地址是否溢出,并在必要时碰撞段寄存器(低效)平面寻址指针在硬件中根本不可能。

快进到 80386 现在我们有了一个完整的 32 位空间。硬件指针是可能的 索引 + 基址寻址会导致 1 个时钟周期的损失。虽然这些段也是 32 位的,因此即使您正在运行 32 位模式,也可以使用段加载数组以避免这种惩罚。368 还将段寄存器的数量增加了 2 个。(不知道为什么 Intel 认为这是个好主意)虽然周围仍然有很多 16 位代码

如今,段寄存器在 64 位模式下被禁用,Base+Index 寻址是免费的。

是否有任何平台可以让平面指针在硬件中胜过数组寻址?嗯,是。1979 年发布的摩托罗拉 68000 有一个平坦的 32 位地址空间,没有段,并且 Base + Index 寻址模式比立即寻址产生 8 个时钟周期的损失。因此,如果您正在编写 80 年代早期的 Sun 电台、Apple Lisa 等,这可能是相关的。

简而言之。如果需要数组,请使用数组。如果你想要一个指针,请使用指针。不要尝试聪明的编译器。将数组转换为指针的复杂代码极不可能提供任何好处,而且可能会更慢。


推荐阅读