c语言指针索引数组,在C中,访问我的数组索引是更快的还是通过指针访问速度更快?...

templatetypedef已经总结了.为他的回应添加一些支持.采取这些示例功能:

unsigned int fun1 ( unsigned int *x )

{

unsigned int ra,rb;

rb=0;

for(ra=0;ra<1000;ra++) rb+=*x++;

return(rb);

}

unsigned int fun2 ( unsigned int *x )

{

unsigned int ra,rb;

rb=0;

for(ra=0;ra<1000;ra++) rb+=x[ra];

return(rb);

}

现在gcc产生了这个:

00000000 fun1:

0: e52d4004 push {r4} ; (str r4,[sp,#-4]!)

4: e1a03000 mov r3,r0

8: e2804efa add r4,r0,#4000 ; 0xfa0

c: e3a00000 mov r0,#0

10: e1a02003 mov r2,r3

14: e492c004 ldr ip,[r2],#4

18: e5931004 ldr r1,[r3,#4]

1c: e2823004 add r3,r2,#4

20: e080000c add r0,ip

24: e1530004 cmp r3,r4

28: e0800001 add r0,r1

2c: 1afffff7 bne 10

30: e49d4004 pop {r4} ; (ldr r4,[sp],#4)

34: e12fff1e bx lr

00000038 fun2:

38: e3a03000 mov r3,#0

3c: e1a02003 mov r2,r3

40: e790c003 ldr ip,[r0,r3]

44: e2833004 add r3,r3,#4

48: e7901003 ldr r1,r3]

4c: e2833004 add r3,#4

50: e082200c add r2,ip

54: e3530efa cmp r3,#4000 ; 0xfa0

58: e0822001 add r2,r1

5c: 1afffff7 bne 40

60: e1a00002 mov r0,r2

64: e12fff1e bx lr

代码是不同的,但我很惊讶于错过的优化机会.

Clang / llvm产生:

00000000 fun1:

0: e3a01000 mov r1,#0

4: e3a02ffa mov r2,#1000 ; 0x3e8

8: e1a03001 mov r3,r1

c: e2522001 subs r2,#1

10: e490c004 ldr ip,[r0],#4

14: e08c3003 add r3,ip,r3

18: e2c11000 sbc r1,r1,#0

1c: e182c001 orr ip,r1

20: e35c0000 cmp ip,#0

24: 1afffff8 bne c

28: e1a00003 mov r0,r3

2c: e12fff1e bx lr

00000030 fun2:

30: e3a01000 mov r1,#0

34: e3a02ffa mov r2,#1000 ; 0x3e8

38: e1a03001 mov r3,r1

3c: e2522001 subs r2,#1

40: e490c004 ldr ip,#4

44: e08c3003 add r3,r3

48: e2c11000 sbc r1,#0

4c: e182c001 orr ip,r1

50: e35c0000 cmp ip,#0

54: 1afffff8 bne 3c

58: e1a00003 mov r0,r3

5c: e12fff1e bx lr

您可能会注意到编译器产生完全相同的代码,指针或偏移量.通过改变编译器,我比改变指针对数组索引更好.我认为llvm可以做得更好一些,我将需要更多的了解这些,以了解我的代码做了什么导致这一点.

编辑:

我希望使编译器至少使用有利于指针的ldr rd,[rs],#4指令,并希望编译器会看到它可能会破坏数组地址,从而将其视为指针而不是偏移量变成一个数组(并使用上面的指令,这基本上是clang / llvm做的).或者如果它使用数组的东西,它将使用ldr rd,[rm,rn]指令.基本上希望编译器之一能够产生以下解决方案之一:

funa:

mov r1,#0

mov r2,#1000

funa_loop:

ldr r3,#4

add r1,r3

subs r2,#1

bne funa_loop

mov r0,r1

bx lr

funb:

mov r1,#0

funb_loop:

ldr r3,r2]

add r1,r3

add r2,#4

cmp r2,#0x4000

bne funb_loop

mov r0,r1

bx lr

func:

mov r1,#4000

subs r2,#4

func_loop:

beq func_done

ldr r3,#4

b func_loop

func_done:

mov r0,r1

bx lr

没有相当的到达那里,但相当接近.这是一个有趣的运动.注意以上是所有的ARM汇编器.

一般来说,(不是我的具体的C代码示例而不一定是ARM),一些流行的架构,您将从一个基于寄存器的地址(ldr r0,[r1])和一个寄存器索引/偏移量的负载(ldr r0,[r1,r2]),其中地址是两个寄存器的总和.一个寄存器理想地是阵列的基址,第二个是索引/偏移量.寄存器的前一个负载自身指向指针,后者指向数组.如果您的C程序不会更改或移动指针或索引,那么在这两种情况下,这意味着一个静态地址被计算,那么使用正常的负载,数组和指针都应该产生相同的指令.对于更有意思的改变指针/索引的情况.

Pointer

ldr r0,[r1]

...

add r1,some number

Array index

ldr r0,r2]

...

add r2,some number

(根据需要用商店替换负载和添加子)

一些架构没有三个注册寄存器索引指令,所以你必须做一些事情

array index:

mov r2,r1

...

ldr r0,[r2]

...

add r2,some number

或者根据编译器可能会变得非常糟糕,esp如果编译用于调试或没有优化,并假设您没有三个寄存器添加

array index:

mov r2,#0

...

mov r3,r1

add r3,r2

ldr r4,[r3]

...

add r2,some number

所以这两种方法很可能是相等的.如在ARM上看到的,它可以将两个(即时)指针指针组合在一起,使其更快一点.阵列索引解决方案会烧写更多的寄存器,并且取决于架构的可用寄存器数量,这些寄存器可能会将寄存器交换到堆栈的时间越来越快(比使用指针)更慢.如果您不介意摧毁基地址,底线是指针解决方案可能会从性能角度给您一个优势.它与您的代码和编译器有很大关系.对我来说,它的可读性发挥作用,我觉得数组更容易阅读和跟随,第二个我需要保留该指针释放一个malloc或再次通过该内存等.如果是这样我可能会使用一个数组与一个索引,如果是一次性通过,我不关心摧毁基地址,我将使用一个指针.如上所述,使用编译器生成的代码,如果性能至关重要,那么手工编译汇编器中的解决方案(根据建议的方法,让编译器先尝试一下).

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值