跃2.0 2018-07-28 01:41 采纳率: 40%
浏览 724
已结题

精通汇编和c的大佬来回答一下:从汇编的角度来理解一下这个函数传参为什么传的是值

最近写函数突然联想到很多问题,比如我们一般说函数传参传的是值不是地址,想要通过函数来修改一个参数的值我们得用指针,然后我想从汇编的角度来理解,就用了非常经典的swap然后反汇编。但是感觉汇编代码不管是传值还是传指针感觉差不多啊。大佬们能不能解释一下,明明函数里的堆栈使用完都会释放嘛,为什么传指针就可以修改呢

 #include<stdio.h>
 int main()
 {
     int a=1;
     int b=2;
     swap(a,b);
     }
     void wap(int a,int b)
     {
        int t=a;
        a=b;
        b=t;
        }
        汇编:
        main:
 10 .LFB0:
 11         .cfi_startproc
 12         lea     ecx, [esp+4]
 12         lea     ecx, [esp+4]
 13         .cfi_def_cfa 1, 0
 14         and     esp, -16
 15         push    DWORD PTR [ecx-4]
 16         push    ebp
 17         .cfi_escape 0x10,0x5,0x2,0x75,0
 18         mov     ebp, esp
 19         push    ecx
 20         .cfi_escape 0xf,0x3,0x75,0x7c,0x6
 21         sub     esp, 20
 22         mov     DWORD PTR [ebp-16], 1
 23         mov     DWORD PTR [ebp-12], 2
 24         sub     esp, 8
 25         push    DWORD PTR [ebp-12]
 26         push    DWORD PTR [ebp-16]
 27         call    swap
 28         add     esp, 16
 29         sub     esp, 4
 30         push    DWORD PTR [ebp-12]
 31         push    DWORD PTR [ebp-16]
 32         push    OFFSET FLAT:.LC0
 33         call    printf
 34         add     esp, 16
 35         mov     eax, 0
 36         mov     ecx, DWORD PTR [ebp-4]
 37         .cfi_def_cfa 1, 0
 38         leave
 39         .cfi_restore 5
 40         lea     esp, [ecx-4]
 41         .cfi_def_cfa 4, 4
 42         ret
 43         .cfi_endproc
 44 .LFE0:
 45         .size   main, .-main
 46         .globl  swap
 47         .type   swap, @function
 48 swap:
 49 .LFB1:
 50         .cfi_startproc
 51         push    ebp
 52         .cfi_def_cfa_offset 8
 53         .cfi_offset 5, -8
 54         mov     ebp, esp
 55         .cfi_def_cfa_register 5
 56         sub     esp, 16
 57         mov     eax, DWORD PTR [ebp+8]
 58         mov     DWORD PTR [ebp-4], eax
 59         mov     eax, DWORD PTR [ebp+12]
 60         mov     DWORD PTR [ebp+8], eax
 61         mov     eax, DWORD PTR [ebp-4]
 62         mov     DWORD PTR [ebp+12], eax
 63         nop
 64         leave
 65         .cfi_restore 5
 66         .cfi_def_cfa 4, 4
 nop
 leave
  ret                                                             

我觉得引用和指针也差不多,,,
#include<stdio.h>
 int main()
 {
     int a=1;
     int b=2;
     swap(&a,&b);
     }
     void wap(int *a,int *b)
     {
        int t=*a;
        *a=*b;
        *b=t;
        }
汇编:
main:
.LFB0:
    .cfi_startproc
    lea ecx, [esp+4]
    .cfi_def_cfa 1, 0
    and esp, -16
    push    DWORD PTR [ecx-4]
    push    ebp
    .cfi_escape 0x10,0x5,0x2,0x75,0
    mov ebp, esp
    push    ecx
    .cfi_escape 0xf,0x3,0x75,0x7c,0x6
    sub esp, 20
    mov eax, DWORD PTR gs:20
    mov DWORD PTR [ebp-12], eax
    xor eax, eax
    mov DWORD PTR [ebp-20], 1
    mov DWORD PTR [ebp-16], 2
    sub esp, 8
    lea eax, [ebp-16]
    push    eax
    lea eax, [ebp-20]
    push    eax
    call    swap
    add esp, 16
    mov edx, DWORD PTR [ebp-16]
    mov eax, DWORD PTR [ebp-20]
    sub esp, 4
    push    edx
    push    eax
    push    OFFSET FLAT:.LC0
    call    printf
    add esp, 16
    mov eax, 0
    mov ecx, DWORD PTR [ebp-12]
    xor ecx, DWORD PTR gs:20
    je  .L3
    call    __stack_chk_fail
.L3:
    mov ecx, DWORD PTR [ebp-4]
    .cfi_def_cfa 1, 0
    leave
    .cfi_restore 5
    lea esp, [ecx-4]
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
.LFE0:
    .size   main, .-main
    .globl  swap
    .type   swap, @function
swap:
.LFB1:
    .cfi_startproc
    push    ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    mov ebp, esp
    .cfi_def_cfa_register 5
    sub esp, 16
    mov eax, DWORD PTR [ebp+8]
    mov eax, DWORD PTR [eax]
    mov DWORD PTR [ebp-4], eax
    mov eax, DWORD PTR [ebp+12]
    mov edx, DWORD PTR [eax]
    mov eax, DWORD PTR [ebp+8]
    mov DWORD PTR [eax], edx
    mov eax, DWORD PTR [ebp+12]
    mov edx, DWORD PTR [ebp-4]
    mov DWORD PTR [eax], edx
    nop
    leave
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc

  • 写回答

4条回答

  • threenewbee 2018-07-28 02:04
    关注

    你那个不是引用,而是传指针
    从汇编的角度看,当然是差不多的,都是传了一个数字嘛。
    只是这个数字代表的含义不同,前者是具体的值,后者是一个地址。(当然,从指针的指针int **的角度看,int 也是一个具体的值,站在 int **的角度看,int **也是具体的值)

    因为int *是指针,如果你把它当作具体的值看待,那么和int是一样的。
    swap(int * a, int * v)
    {
    int t;
    a = &t;
    b = a;
    a = t;
    }
    这个代码就和你
    swap(int a, int b)
    一样,虽然修改了a, b,但是不会有效果。

    而swap(int * a, int * b)
    {
    int t;
    t = *a;
    *a = *b;
    *b = t;
    }
    之所以能成功,是因为它并没有修改a,b,而是修改的是a b指向的对象

    你仔细对比这两个程序,就明白了。

    评论

报告相同问题?

悬赏问题

  • ¥15 完成下列问题完成下列问题
  • ¥15 C#算法问题, 不知道怎么处理这个数据的转换
  • ¥15 YoloV5 第三方库的版本对照问题
  • ¥15 请完成下列相关问题!
  • ¥15 drone 推送镜像时候 purge: true 推送完毕后没有删除对应的镜像,手动拷贝到服务器执行结果正确在样才能让指令自动执行成功删除对应镜像,如何解决?
  • ¥15 求daily translation(DT)偏差订正方法的代码
  • ¥15 js调用html页面需要隐藏某个按钮
  • ¥15 ads仿真结果在圆图上是怎么读数的
  • ¥20 Cotex M3的调试和程序执行方式是什么样的?
  • ¥20 java项目连接sqlserver时报ssl相关错误