zoukankan      html  css  js  c++  java
  • C语言数组操作和指针操作谁更高效

    在上一篇博文  代码优化小技巧(持续更新......) 第三条关于数组和指针谁更高效, 意犹未尽, 决定单独拉出一篇来讲

    1. 数组和指针操作对比
    #include <stdio.h>
    
    int main()
    {
            char *char_p, char_arr[5]={0,1,2};
            short *short_p, short_arr[5]={1,2,3};
            int *int_p, int_arr[5]={2,3,4};
    
            char_p=char_arr;
            short_p=short_arr;
            int_p=int_arr;
    
            printf("111
    ");
            (*(char_p+2)) ++;
            printf("222
    ");
            char_arr[2] ++;
    
            printf("111
    ");
            (*(short_p+2)) ++;
            printf("222
    ");
            short_arr[2] ++;
    
            printf("111
    ");
            (*(int_p+2)) ++;
            printf("222
    ");
            int_arr[2] ++;
    
            return 0;
    }

    编译和反汇编

    <main>:
      400596:       55                      push   %rbp
      400597:       48 89 e5                mov    %rsp,%rbp
      40059a:       48 83 ec 60             sub    $0x60,%rsp
      40059e:       64 48 8b 04 25 28 00    mov    %fs:0x28,%rax
      4005a5:       00 00 
      4005a7:       48 89 45 f8             mov    %rax,-0x8(%rbp)
      4005ab:       31 c0                   xor    %eax,%eax
      4005ad:       c7 45 f0 00 00 00 00    movl   $0x0,-0x10(%rbp)
      4005b4:       c6 45 f4 00             movb   $0x0,-0xc(%rbp)
      4005b8:       c6 45 f1 01             movb   $0x1,-0xf(%rbp)
      4005bc:       c6 45 f2 02             movb   $0x2,-0xe(%rbp)
      4005c0:       48 c7 45 c0 00 00 00    movq   $0x0,-0x40(%rbp)
      4005c7:       00 
      4005c8:       66 c7 45 c8 00 00       movw   $0x0,-0x38(%rbp)
      4005ce:       66 c7 45 c0 01 00       movw   $0x1,-0x40(%rbp)
      4005d4:       66 c7 45 c2 02 00       movw   $0x2,-0x3e(%rbp)
      4005da:       66 c7 45 c4 03 00       movw   $0x3,-0x3c(%rbp)
      4005e0:       48 c7 45 d0 00 00 00    movq   $0x0,-0x30(%rbp)
      4005e7:       00 
      4005e8:       48 c7 45 d8 00 00 00    movq   $0x0,-0x28(%rbp)
      4005ef:       00 
      4005f0:       c7 45 e0 00 00 00 00    movl   $0x0,-0x20(%rbp)
      4005f7:       c7 45 d0 02 00 00 00    movl   $0x2,-0x30(%rbp)
      4005fe:       c7 45 d4 03 00 00 00    movl   $0x3,-0x2c(%rbp)
      400605:       c7 45 d8 04 00 00 00    movl   $0x4,-0x28(%rbp)
      40060c:       48 8d 45 f0             lea    -0x10(%rbp),%rax
      400610:       48 89 45 a8             mov    %rax,-0x58(%rbp)
      400614:       48 8d 45 c0             lea    -0x40(%rbp),%rax
      400618:       48 89 45 b0             mov    %rax,-0x50(%rbp)
      40061c:       48 8d 45 d0             lea    -0x30(%rbp),%rax
      400620:       48 89 45 b8             mov    %rax,-0x48(%rbp)
      400624:       bf 54 07 40 00          mov    $0x400754,%edi
      400629:       e8 32 fe ff ff          callq  400460 <puts@plt>
      40062e:       48 8b 45 a8             mov    -0x58(%rbp),%rax
      400632:       48 83 c0 02             add    $0x2,%rax
      400636:       0f b6 10                movzbl (%rax),%edx
      400639:       83 c2 01                add    $0x1,%edx
      40063c:       88 10                   mov    %dl,(%rax)
      40063e:       bf 58 07 40 00          mov    $0x400758,%edi
      400643:       e8 18 fe ff ff          callq  400460 <puts@plt>
      400648:       0f b6 45 f2             movzbl -0xe(%rbp),%eax
      40064c:       83 c0 01                add    $0x1,%eax
      40064f:       88 45 f2                mov    %al,-0xe(%rbp)
      400652:       bf 54 07 40 00          mov    $0x400754,%edi
      400657:       e8 04 fe ff ff          callq  400460 <puts@plt>
      40065c:       48 8b 45 b0             mov    -0x50(%rbp),%rax
      400660:       48 83 c0 04             add    $0x4,%rax
      400664:       0f b7 10                movzwl (%rax),%edx
      400667:       83 c2 01                add    $0x1,%edx
      40066a:       66 89 10                mov    %dx,(%rax)
      40066d:       bf 58 07 40 00          mov    $0x400758,%edi
      400672:       e8 e9 fd ff ff          callq  400460 <puts@plt>
      400677:       0f b7 45 c4             movzwl -0x3c(%rbp),%eax
      40067b:       83 c0 01                add    $0x1,%eax
      40067e:       66 89 45 c4             mov    %ax,-0x3c(%rbp)
      400682:       bf 54 07 40 00          mov    $0x400754,%edi
      400687:       e8 d4 fd ff ff          callq  400460 <puts@plt>
      40068c:       48 8b 45 b8             mov    -0x48(%rbp),%rax
      400690:       48 83 c0 08             add    $0x8,%rax
      400694:       8b 10                   mov    (%rax),%edx
      400696:       83 c2 01                add    $0x1,%edx
      400699:       89 10                   mov    %edx,(%rax)
      40069b:       bf 58 07 40 00          mov    $0x400758,%edi
      4006a0:       e8 bb fd ff ff          callq  400460 <puts@plt>
      4006a5:       8b 45 d8                mov    -0x28(%rbp),%eax
      4006a8:       83 c0 01                add    $0x1,%eax
      4006ab:       89 45 d8                mov    %eax,-0x28(%rbp)
      4006ae:       b8 00 00 00 00          mov    $0x0,%eax
      4006b3:       48 8b 4d f8             mov    -0x8(%rbp),%rcx
      4006b7:       64 48 33 0c 25 28 00    xor    %fs:0x28,%rcx
      4006be:       00 00 
      4006c0:       74 05                   je     4006c7 <main+0x131>
      4006c2:       e8 a9 fd ff ff          callq  400470 <__stack_chk_fail@plt>
      4006c7:       c9                      leaveq 
      4006c8:       c3                      retq   
      4006c9:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)
    x86编译和反汇编
    0000842c <main>:
        842c:       e92d4800        push    {fp, lr}
        8430:       e28db004        add     fp, sp, #4
        8434:       e24dd038        sub     sp, sp, #56     ; 0x38
        8438:       e3a03000        mov     r3, #0
        843c:       e50b3018        str     r3, [fp, #-24]  ; 0xffffffe8
        8440:       e3a03000        mov     r3, #0
        8444:       e54b3014        strb    r3, [fp, #-20]  ; 0xffffffec
        8448:       e3a03001        mov     r3, #1
        844c:       e54b3017        strb    r3, [fp, #-23]  ; 0xffffffe9
        8450:       e3a03002        mov     r3, #2
        8454:       e54b3016        strb    r3, [fp, #-22]  ; 0xffffffea
        8458:       e24b3024        sub     r3, fp, #36     ; 0x24
        845c:       e3a02000        mov     r2, #0
        8460:       e5832000        str     r2, [r3]
        8464:       e2833004        add     r3, r3, #4
        8468:       e3a02000        mov     r2, #0
        846c:       e5832000        str     r2, [r3]
        8470:       e2833004        add     r3, r3, #4
        8474:       e3a02000        mov     r2, #0
        8478:       e1c320b0        strh    r2, [r3]
        847c:       e2833002        add     r3, r3, #2
        8480:       e3a03001        mov     r3, #1
        8484:       e14b32b4        strh    r3, [fp, #-36]  ; 0xffffffdc
        8488:       e3a03002        mov     r3, #2
        848c:       e14b32b2        strh    r3, [fp, #-34]  ; 0xffffffde
        8490:       e3a03003        mov     r3, #3
        8494:       e14b32b0        strh    r3, [fp, #-32]  ; 0xffffffe0
        8498:       e24b3038        sub     r3, fp, #56     ; 0x38
        849c:       e3a02000        mov     r2, #0
        84a0:       e5832000        str     r2, [r3]
        84a4:       e2833004        add     r3, r3, #4
        84a8:       e3a02000        mov     r2, #0
        84ac:       e5832000        str     r2, [r3]
        84b0:       e2833004        add     r3, r3, #4
        84b4:       e3a02000        mov     r2, #0
        84b8:       e5832000        str     r2, [r3]
        84bc:       e2833004        add     r3, r3, #4
        84c0:       e3a02000        mov     r2, #0
        84c4:       e5832000        str     r2, [r3]
        84c8:       e2833004        add     r3, r3, #4
        84cc:       e3a02000        mov     r2, #0
        84d0:       e5832000        str     r2, [r3]
        84d4:       e2833004        add     r3, r3, #4
        84d8:       e3a03002        mov     r3, #2
        84dc:       e50b3038        str     r3, [fp, #-56]  ; 0xffffffc8
        84e0:       e3a03003        mov     r3, #3
        84e4:       e50b3034        str     r3, [fp, #-52]  ; 0xffffffcc
        84e8:       e3a03004        mov     r3, #4
        84ec:       e50b3030        str     r3, [fp, #-48]  ; 0xffffffd0
        84f0:       e24b3018        sub     r3, fp, #24
        84f4:       e50b3008        str     r3, [fp, #-8]
        84f8:       e24b3024        sub     r3, fp, #36     ; 0x24
        84fc:       e50b300c        str     r3, [fp, #-12]
        8500:       e24b3038        sub     r3, fp, #56     ; 0x38
        8504:       e50b3010        str     r3, [fp, #-16]
        8508:       e59f00b0        ldr     r0, [pc, #176]  ; 85c0 <main+0x194>
        850c:       ebffff8f        bl      8350 <_init+0x20>
        8510:       e51b3008        ldr     r3, [fp, #-8]
        8514:       e2833002        add     r3, r3, #2
        8518:       e5d32000        ldrb    r2, [r3]
        851c:       e2822001        add     r2, r2, #1
        8520:       e20220ff        and     r2, r2, #255    ; 0xff
        8524:       e5c32000        strb    r2, [r3]
        8528:       e59f0094        ldr     r0, [pc, #148]  ; 85c4 <main+0x198>
        852c:       ebffff87        bl      8350 <_init+0x20>
        8530:       e55b3016        ldrb    r3, [fp, #-22]  ; 0xffffffea
        8534:       e2833001        add     r3, r3, #1
        8538:       e20330ff        and     r3, r3, #255    ; 0xff
        853c:       e54b3016        strb    r3, [fp, #-22]  ; 0xffffffea
        8540:       e59f0078        ldr     r0, [pc, #120]  ; 85c0 <main+0x194>
        8544:       ebffff81        bl      8350 <_init+0x20>
        8548:       e51b300c        ldr     r3, [fp, #-12]
        854c:       e2833004        add     r3, r3, #4
        8550:       e1d320b0        ldrh    r2, [r3]
        8554:       e2822001        add     r2, r2, #1
        8558:       e1a02802        lsl     r2, r2, #16
        855c:       e1a02822        lsr     r2, r2, #16
        8560:       e1c320b0        strh    r2, [r3]
        8564:       e59f0058        ldr     r0, [pc, #88]   ; 85c4 <main+0x198>
        8568:       ebffff78        bl      8350 <_init+0x20>
        856c:       e15b32b0        ldrh    r3, [fp, #-32]  ; 0xffffffe0
        8570:       e2833001        add     r3, r3, #1
        8574:       e1a03803        lsl     r3, r3, #16
        8578:       e1a03823        lsr     r3, r3, #16
        857c:       e14b32b0        strh    r3, [fp, #-32]  ; 0xffffffe0
        8580:       e59f0038        ldr     r0, [pc, #56]   ; 85c0 <main+0x194>
        8584:       ebffff71        bl      8350 <_init+0x20>
        8588:       e51b3010        ldr     r3, [fp, #-16]
        858c:       e2833008        add     r3, r3, #8
        8590:       e5932000        ldr     r2, [r3]
        8594:       e2822001        add     r2, r2, #1
        8598:       e5832000        str     r2, [r3]
        859c:       e59f0020        ldr     r0, [pc, #32]   ; 85c4 <main+0x198>
        85a0:       ebffff6a        bl      8350 <_init+0x20>
        85a4:       e51b3030        ldr     r3, [fp, #-48]  ; 0xffffffd0
        85a8:       e2833001        add     r3, r3, #1
        85ac:       e50b3030        str     r3, [fp, #-48]  ; 0xffffffd0
        85b0:       e3a03000        mov     r3, #0
        85b4:       e1a00003        mov     r0, r3
        85b8:       e24bd004        sub     sp, fp, #4
        85bc:       e8bd8800        pop     {fp, pc}
        85c0:       000086a0        .word   0x000086a0
        85c4:       000086a4        .word   0x000086a4
    arm编译和反汇编

    横向对比:

     

      这里可以很明显得出结论: 使用数组操作比指针高效!, 理由很简单, 编译器认为数组偏移多少成员其对于地址都是确定的, 取数组[0]和[3]没有区别就是个地址, 而指针偏移是一个独立行为,

    所以要显性执行这个动作, 因此多出这部分指令!

      这个表还有其他有意思的地方, 比如用int变量比char、short高效, char要and或者movzbl屏蔽溢出, short要lsl/lsr左移右移等

      另外就是x86可以直接通过mov操作内存, 而ARM结构采用load-store, 必须先加载到寄存器, 进行操作后再回写内存

     2. 指针作为函数参数(x86编译为例)
    #include <stdio.h>
    
    void test1(int *p)
    {
        (*(p+4))++;
    }
    
    void test2(int *p)
    {
        p[4]++;
    }
    
    int main()
    {
        char *char_p, char_arr[5]={0,1,2};
        short *short_p, short_arr[5]={1,2,3};
        int *int_p, int_arr[5]={2,3,4};
    
        char_p=char_arr;
        short_p=short_arr;
        int_p=int_arr;
    
        /* 省略上面测试代码*/
    
        printf("333
    ");
        test1(int_p);
        test2(int_p);
        printf("444
    ");
        test1(int_arr);
        test2(int_arr);
    
        return 0;
    }

    可以发现test1()、test2()反汇编实现是一样的, 不会因为“形式”上我用数组还是指针, 最终的本质是指针, 而调用无论传的是数组地址还是指针地址, 没有影响, 都是地址值而已

    0000000000400596 <test1>:
      400596:       55                      push   %rbp
      400597:       48 89 e5                mov    %rsp,%rbp
      40059a:       48 89 7d f8             mov    %rdi,-0x8(%rbp)
      40059e:       48 8b 45 f8             mov    -0x8(%rbp),%rax
      4005a2:       48 83 c0 10             add    $0x10,%rax
      4005a6:       8b 10                   mov    (%rax),%edx
      4005a8:       83 c2 01                add    $0x1,%edx
      4005ab:       89 10                   mov    %edx,(%rax)
      4005ad:       90                      nop
      4005ae:       5d                      pop    %rbp
      4005af:       c3                      retq   
    
    00000000004005b0 <test2>:
      4005b0:       55                      push   %rbp
      4005b1:       48 89 e5                mov    %rsp,%rbp
      4005b4:       48 89 7d f8             mov    %rdi,-0x8(%rbp)
      4005b8:       48 8b 45 f8             mov    -0x8(%rbp),%rax
      4005bc:       48 83 c0 10             add    $0x10,%rax
      4005c0:       8b 10                   mov    (%rax),%edx
      4005c2:       83 c2 01                add    $0x1,%edx
      4005c5:       89 10                   mov    %edx,(%rax)
      4005c7:       90                      nop
      4005c8:       5d                      pop    %rbp
      4005c9:       c3                      retq   
    
    
    
      4006e7:       e8 74 fd ff ff          callq  400460 <puts@plt>
      4006ec:       48 8b 45 b8             mov    -0x48(%rbp),%rax
      4006f0:       48 89 c7                mov    %rax,%rdi
      4006f3:       e8 9e fe ff ff          callq  400596 <test1>
      4006f8:       48 8b 45 b8             mov    -0x48(%rbp),%rax
      4006fc:       48 89 c7                mov    %rax,%rdi
      4006ff:       e8 ac fe ff ff          callq  4005b0 <test2>
      400704:       bf e0 07 40 00          mov    $0x4007e0,%edi
      400709:       e8 52 fd ff ff          callq  400460 <puts@plt>
      40070e:       48 8d 45 d0             lea    -0x30(%rbp),%rax
      400712:       48 89 c7                mov    %rax,%rdi
      400715:       e8 7c fe ff ff          callq  400596 <test1>
      40071a:       48 8d 45 d0             lea    -0x30(%rbp),%rax
      40071e:       48 89 c7                mov    %rax,%rdi
      400721:       e8 8a fe ff ff          callq  4005b0 <test2>
     3. 数组作为函数参数(x86编译为例)
    代码和上面一样就不贴了, 只是将参数改成数组
    /*
    void test1(int *p)
    {
        (*(p+4))++;
    }
    
    void test2(int *p)
    {
        p[4]++;
    }
    */
    void test1(int p[])
    {
        (*(p+4))++;
    }
    
    void test2(int p[])
    {
        p[4]++;
    }

     反汇编的结果发现和上面函数形参是指针的一模一样!  也就是说虽然我的参数看起来像数组, 但实际上由于没有指定成员数量实际分配内存, 所以编译器还是把参数当做指针对待!

     结论:

      a. “真实”数组操作比指针高效

      b. 有些看起来像数组, 实质是指针的, 指令走的还是指针那一套, 无论语法写的是*p++还是p[i]

  • 相关阅读:
    android高级UI之Paint Xfermode
    android高级UI之Paint滤镜
    常见文献管理软件
    linux下10款markdown软件
    markdown页面内跳转
    Ubuntu18.04配制阿里巴巴的源
    python中TAB补全
    word中手动添加endnote的加载项
    MarkDown添加图片的三种方式
    word前页与后页页码断开
  • 原文地址:https://www.cnblogs.com/vedic/p/10648648.html
Copyright © 2011-2022 走看看