Allen Zhao的学习笔记

非淡泊无以明志,非宁静无以致远。

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

       以前写过一篇阐述C语言中指针和数组区别的文章,最近很后知后觉地读《C专家编程》时发现居然有三章是在详细说这个问题,读完后算是把这个问题搞得更透彻了。遂用一组C源码和汇编码的对比来再次展示它们的区别。

 

        (试验环境:Ubuntu Linux/GCC)

 

源码(test.c):

int fun1()
{
int a[1],b[1],*p=b;

a[0]=0;
*(p+0)=1;

return 0;
}

 

 

免优化汇编码(gcc -S test.c):

.file "test.c"

.text
.globl fun1
.type fun1, @function
fun1:
pushl %ebp
movl %esp, %ebp
subl $16, %esp
leal -8(%ebp), %eax
movl %eax, -12(%ebp)
movl $0, -4(%ebp)
movl -12(%ebp), %eax
movl $1, (%eax)
movl $0, %eax
leave
ret
.size fun1, .-fun1
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5.1) 4.4.3"
.section .note.GNU-stack,"",@progbits

 

 

        通过汇编码可以清晰地看到,当如果数组是通过a[0]这种形式定义的,那么在访问它时数组名会直接被转成地址(不经过二次寻址过程),而下标就是偏移量:movl $0, -4(%ebp)。而若通过指针去操作数组,则会经历二次寻址:先把指针中的值取出(movl -12(%ebp), %eax),再通过这个值加偏移量去访问目标元素(movl $1, (%eax))。即在这种情况下,对数组和指针的访问机理是不同的。

 

        还有另外一种情况,就是数组被当作参数传递给子程序,比如:

void fun(int a[])
{
        a[0]=1;
}

汇编码为:

        .file   "test.c"
        .text
.globl fun
        .type   fun, @function
fun:
        pushl   %ebp
        movl    %esp, %ebp
        movl    8(%ebp), %eax
        movl    $1, (%eax)
        popl    %ebp
        ret
        .size   fun, .-fun
        .ident  "GCC: (Ubuntu 4.4.3-4ubuntu5.1) 4.4.3"
        .section        .note.GNU-stack,"",@progbits

 

        我们可以看到,当数组被当作参数传给子程序后,实际上是被转换成了指针,在子函数中堆元素的操作也是通过了“二次取址”过程。

posted on 2012-04-29 14:01  Allen Zhao  阅读(362)  评论(0编辑  收藏  举报