数组和指针的对比---指针一定效率高吗


前言

在这个专栏的第一期里,笔者以实际项目中看到的一个模型,分析了指针类型对地址取值的影响。这一期,还是围绕指针这个重头戏,分析下数组和指针的异同。


一、指针和数组可以互换使用吗?

数组可以认为是一系列相同类型连续排列数据的集合,指针是指向一定类型数据的变量。单从定义上看,两者就不同了。参考以下2个说明:

int a[5];
int *b;

这里,可以让以上的指针b指向数组的首地址:

b = &a[0];

但不考虑上述赋值的情况,在编译器编译时,对两者的行为会有什么不同呢?
很显然两者不能简单的互换
在编译时,对于一个数组,编译器首先指定数组元素的数量,留给数组足够的空间给每个元素使用,而之后才会创建数组名,且这个数组的各个元素的地址都确定下来;
对于一个指针,编译器只为指针本身保留内存空间,而他具体指向的位置还是不确定的。如果之后不给这个指针赋值,那么这个指针就认为是个“野指针”。
数组和指针对比

二、指针一定比数组效率高吗?

这里以VS2010x86编译器为例,针对实现同样功能的两种函数形式,利用VS自带的dumpbin反汇编工具,对比下用数组和指针实现时,具体在执行代码时的效率。
分别使用数组和指针两种方式,实现数组y到数组x里50个元素的copy:

#define	SIZE	50
int x[SIZE];
int y[SIZE];
int i;
int *p1, *p2;

void 
try1()
{
	for(i=0; i<SIZE; i++){
		x[i] = y[i];
	}
}

void
try2()
{
	register int *p1, *p2;
	register int i;

	for(i=0, p1=x, p2=y; i<SIZE; i++){
		*p1++ = *p2++;
	}
}

方法1对应try1 fuction,方法2对应try2 function。设置编译器参数使得在不优化和优化的两种情况下,对比编译后的obj在反编译为汇编时的行为:

1.不加入Ox优化选项

try1 function的反汇编结果如下:
try1 function的反汇编结果
可以看出,编译器为了实现数组中每个元素的copy,将数组下标i进行乘法运算来取值进行copy;如果某个硬件架构所支持的乘法运算周期较长,那么该case下明显会降低程序运行的效率。
try2 function的反汇编结果如下:
try2 function的反汇编结果
可以看出,编译器在编译时,将数组x和数组y的首地址分别放在了堆栈中[ebp-8]和[ebp-14h]的位置。而后对数组中每个成员的遍历,均依靠的是前一个数组单元地址的基础上+4的方法,因此这样效率明显高一些。但同时可以看到,在每次调整完数组下标后,将数组元素地址又重新塞进了堆栈中,也存在一些待优化的地方。

2.加入Ox优化选项

try1()和try2()的反汇编结果:

try1()和try2()的反汇编结果
这时,可以惊喜的看到,两者的反汇编代码是相同的
在采用优化大小或者优化速度的选项后,数组元素的copy过程,完全由rep movs指令实现!即采用edi和esi寄存器,指定ecx巧妙的实现:

rep movs dword ptr es:[edi], dword ptr [esi]

总结

最后,想必读者心中都有了一份答案。
指针不能简单的和数组互换,而且在编译器如此智能的今天,指针也不一定比数组效率高了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cerman

你的鼓励是探索和创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值