用数组和指针访问数据,哪个快?

mbctb 2010-03-20 02:26:40
一直觉得用数组下标访问数据比指针快,原因是:数组名在编译时已经是个常数了,用数据下标访问数据,实际上就是直接用指令里的地址去取。而用指针访问,要先取指针的值,然后根据指针的值(作为一个地址),再去访问数据。多了一个步骤,当然就慢了。

今天在网上看到这样一篇贴子,与我有同样的疑问:


谭浩强老师的《C语言程序设计》第二版,page211页,有这样一段话:

引用数组元素可以用下标法,也可以用指针法,即通过指向数组元素的指针找到所需的元素。使用指针法能使目标程序质量高(占内存少,运行速度快)。

每次看到这个地方我都有点不解。后来在VC6.0环境下想了个实验办法,编写一个简单的控制台程序,利用反汇编工具察看编译后的代码,发现好像不是这样子的。从下面代码看,好像利用指针访问数组元素要比下标法要慢。

代码如下:

#include <stdio.h>

void main()
{
int i;
int a[10]={10,20};
int *b=a;
printf("%d",1);
printf("%c",a[0]);
printf("%c",a[1]); *****************使用下标法
printf("%c",*b); *****************指针法
printf("%c",*(b+1)); *****************这几句话的汇编代码
printf("%d",2);
}

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

下面是反汇编的结果:

7: printf("%c",a[0]);
0040B797 mov ecx,dword ptr [ebp-2Ch]
0040B79A push ecx ****************这里是下标法编译后汇编语句
0040B79B push offset string "%c" (0042001c)
0040B7A0 call printf (00401060)
0040B7A5 add esp,8
8: printf("%c",a[1]);
0040B7A8 mov edx,dword ptr [ebp-28h]
0040B7AB push edx
0040B7AC push offset string "%c" (0042001c)
0040B7B1 call printf (00401060)
0040B7B6 add esp,8
9: printf("%c",*b);
0040B7B9 mov eax,dword ptr [ebp-30h]
0040B7BC mov ecx,dword ptr [eax]

0040B7BE push ecx ****************这里是指针法编译后汇编语句
0040B7BF push offset string "%c" (0042001c)
0040B7C4 call printf (00401060)
0040B7C9 add esp,8
10: printf("%c",*(b+1));
0040B7CC mov edx,dword ptr [ebp-30h]
0040B7CF mov eax,dword ptr [edx+4]
0040B7D2 push eax
0040B7D3 push offset string "%c" (0042001c)
0040B7D8 call printf (00401060)
0040B7DD add esp,8


在上面程序中,利用下标访问数组的语句编译后的汇编语句只有2句,而利用指针访问数组元素编译后有3句,显然是利用下标法进行访问比较快些。所以对谭老师书上的那一段话有些质疑。特在此贴出来,希望有心达人能给我补充下,也给那些关注这些问题的喜欢C语言的新朋友提个问题。


大家觉得呢?用指针快还是数组下标快?
...全文
3227 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
失落的凡凡 2010-03-20
  • 打赏
  • 举报
回复
我来解开楼主的疑惑吧

#define SIZE 200
void test1(int);
void test2(int);
void test3(int);

void a()
{
int a[SIZE];
int i=0;
for(; i < SIZE; i++)
{
test1(a[i]);
/* test2(a[i]);
* test3(a[i]);
*/
}
}
void b()
{
int a[SIZE];
int *p = a;
int *pend = a+SIZE;
for(; p != pend; p++)
{
test1(*p);
/* test2(*p);
* test3(*p);
*/
}
}

用GCC -O2 -S 编译后得到如下代码:


_a:
pushl %ebp
movl %esp, %ebp
pushl %ebx
subl $820, %esp
xorl %ebx, %ebx
.p2align 4,,15
L5: // 函数a中的for循环开始 这里实际上被优化为do……while循环
movl -808(%ebp,%ebx,4), %eax // 把a[i]的值放到寄存器%eax中 MARK
incl %ebx // i++;
movl %eax, (%esp) // 把a[i]当作参数压入栈
call _test1 // 调用函数test1
cmpl $199, %ebx // 比较i 和 199
jle L5 // 如果比较结果是否小于等于等于跳回L5
addl $820, %esp
popl %ebx
popl %ebp
ret
.p2align 4,,15
.globl _b
.def _b; .scl 2; .type 32; .endef
_b:
pushl %ebp
movl %esp, %ebp
pushl %esi
leal -8(%ebp), %esi
pushl %ebx
subl $816, %esp
leal -808(%ebp), %ebx
.p2align 4,,15
L13: // 函数b 中的for循环开始 这里同样被优化为do……while循环
movl (%ebx), %eax // 把指针p指向的值放到寄存器%eax中 MARK
addl $4, %ebx // 指针p 加4 (4 == sizeof(int) )
movl %eax, (%esp) // 把指针p指向的值压入栈
call _test1 // 调用函数test1
cmpl %esi, %ebx // 比较指针p 和pend
jne L13 // 如果不相等则返回L13(继续循环)
addl $816, %esp
popl %ebx
popl %esi
popl %ebp
ret

注意标MARK的两行,“用指针比用下标快”的关键就在于此。这是两种不同的寻址方式,下面这种快于上面的。

两种不同寻址方式带来的性能差异,真的真的是太微不足道了……
cattycat 2010-03-20
  • 打赏
  • 举报
回复
现在的机器这种速度已经微不足道了,有的编译器会自动给你优化了。其实你想,数组下标是很容易转为指针的,编译器就可以搞定。
arong1234 2010-03-20
  • 打赏
  • 举报
回复
赞同!这种揪住一两个指令周期的东西不放已经不合时宜了。即使真的某种方法快点,算法的复杂度使得这种损耗已经微不足道了!
[Quote=引用 4 楼 jackyjkchen 的回复:]
简单的用指令数量来判断快慢是不对的,而且你一定用的是debug无优化的编译,由于指针访问此事和数组下标等价,说不定编译器干脆将他们编译成完全一样的也说不准。

只要你不使用tc,不用谭浩强的书,那种什么下标快还是数组快、单行循环加不加括号是否影响速度这一类的问题全是伪命题,不值得讨论
[/Quote]
findcsdn 2010-03-20
  • 打赏
  • 举报
回复
数组名就是一个指针,不是常量,但是这个指针不占用任何内存,编译器直接用类似 dword ptr [ebp-2Ch] 的方法表示。

指针 *(P+1) 和 a[1] 的速度应该一样的快,

看看下面的代码就知道是一样的。



#include<stdio.h>

void main()
{
int i;
int a[10]={10, 20};

printf("%d\n",1);
printf("%d\n",a[0]);
printf("%d\n",a[1]); //*****************使用下标法
printf("%d\n",*a); //*****************指针法
printf("%d\n",*(a+1)); //*****************这几句话的汇编代码
printf("%d\n",2);
}

失落的凡凡 2010-03-20
  • 打赏
  • 举报
回复
数组名在编译时也不是常数,而是基于帧的偏移值。一般说指针比下标快,是指在遍历数组的时候。
你写的这些看出出什么来
jackyjkchen 2010-03-20
  • 打赏
  • 举报
回复
简单的用指令数量来判断快慢是不对的,而且你一定用的是debug无优化的编译,由于指针访问此事和数组下标等价,说不定编译器干脆将他们编译成完全一样的也说不准。

只要你不使用tc,不用谭浩强的书,那种什么下标快还是数组快、单行循环加不加括号是否影响速度这一类的问题全是伪命题,不值得讨论
失落的凡凡 2010-03-20
  • 打赏
  • 举报
回复
如果编译器没有优化,是指针快……
优化了,一样快……

这个优化很容易,一般的编译器对此都是义不容辞
Peter200694013 2010-03-20
  • 打赏
  • 举报
回复
指针(存的是地址...)
BT六眼飞鱼 2010-03-20
  • 打赏
  • 举报
回复
用指针快

33,311

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 新手乐园
社区管理员
  • 新手乐园社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧