通过汇编来理解C语言的指针

临时开通了这个blog,希望把最近学习的内容记录下来。


一道出现段错误的指针题:


#include <stdio.h>

     int a;

    void func(int *p)
{
    p = &a;
}
int main(void)
{
    int *p;
    func(p);
    *p = 100;
    return 0;
}


gcc编译后发现段错误,我很难发现错误的原因,不过对传参第过程的确有疑问。

于是gcc -S 反汇编一下,得到:


.file    "ptice.c"
    .comm    a,4,4
    .text
.globl func
    .type    func, @function
func:
    pushl    %ebp
    movl    %esp, %ebp
    movl    $a, 8(%ebp)
    popl    %ebp
    ret
    .size    func, .-func
.globl main
    .type    main, @function
main:
    pushl    %ebp
    movl    %esp, %ebp
    subl    $20, %esp
    movl    -4(%ebp), %eax
    movl    %eax, (%esp)
    call    func
    movl    -4(%ebp), %eax
    movl    $100, (%eax)
    movl    $0, %eax
    leave
    ret
    .size    main, .-main
    .ident    "GCC: (Ubuntu 4.4.1-4ubuntu9) 4.4.1"
    .section    .note.GNU-stack,"",@progbits


发现main函数在call func之前:

    movl    -4(%ebp), %eax
    movl    %eax, (%esp)

明显的错误,把ebp的下4字节的内容移动到当前esp所指向的内容,实际上做了一个*p的副本,为func函数使用;

调用func函数后:

    movl    $a, 8(%ebp)

于是,func函数操作的只是*p的副本,把副本里存放了a的首地址。

ret回main函数后,变量a赋值为100,main函数里的*p,是不知道的,因为,只有它的副本知道。


于是可对.c文件做如下修改:


#include <stdio.h>

     int a;

    void func(int **p)
{
    *p = &a;
}
int main(void)
{
    int *p;
    func(&p);
    *p = 100;
    return 0;
}


即:我们传入的参数是指针p的首地址,而接收参数的是指针p的指针(*p的指针)

反观汇编:


    .file    "ptice.c"
    .comm    a,4,4
    .text
.globl func
    .type    func, @function
func:
    pushl    %ebp
    movl    %esp, %ebp
    movl    8(%ebp), %eax
    movl    $a, (%eax)
    popl    %ebp
    ret
    .size    func, .-func
.globl main
    .type    main, @function
main:
    pushl    %ebp
    movl    %esp, %ebp
    subl    $20, %esp
    leal    -4(%ebp), %eax
    movl    %eax, (%esp)
    call    func
    movl    -4(%ebp), %eax
    movl    $100, (%eax)
    movl    $0, %eax
    leave
    ret
    .size    main, .-main
    .ident    "GCC: (Ubuntu 4.4.1-4ubuntu9) 4.4.1"
    .section    .note.GNU-stack,"",@progbits


我们发现只有一个地方发生了改变:

main函数在call func之前:

    leal    -4(%ebp), %eax
    movl    %eax, (%esp)

mov指令变成了lea指令,也就是说,作为副本供func函数使用的不是ebp下4个字节的内容,而是内容里所指向的地址(即mian函数*p的地址)。


我们gcc正确的程序,发现没有段错误。加一句:

    printf("a = %d/n",a);

结果是预期的100.


指针的作用有了凸显。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值