c文件汇编后函数参数传递的不同之处

 更新时间:2013年11月15日 15:15:02   作者:  
在w7 32位系统下把c文件汇编后,确实与mac后的差异很大。可不仅仅是寄存器eax与rax的区别。我想说的是函数参数传递的不同

mac下clang编译后函数的参数先保存在寄存器中(以一定的规则保存),然后在函数中压入栈里,
以待后用。例如上篇例子,红色部分:

复制代码 代码如下:

.global _decToBin

 _decToBin:
     pushq     %rbp
     movq    %rsp,%rbp

     movq     %rdi,-8(%rbp) #第一个参数,保存在rdi中
     movq     %rsi,-16(%rbp) #第二个参数,保存在rsi中

     movq    -8(%rbp),%rax
     movq    -16(%rbp),%rbx
     movq    $63,%rcx

......

     popq     %rbp
     ret

而我在w7下使用cygwin安装的gcc编译test.c文件:

test.c:

复制代码 代码如下:

int hello(int a,int b,int c,int d)
{
    return b;
}

test.c
复制代码 代码如下:

.file    "test.c"
    .text
    .globl    _hello
    .def    _hello;    .scl    2;    .type    32;    .endef
_hello:
    pushl    %ebp
    movl    %esp, %ebp
    movl    12(%ebp), %eax #说明参数是函数在使用其值之前就已经压入栈中
    popl    %ebp
    ret

这说明clang与gcc使用了两种不同的规则(网上有很多介绍函数值传递的不同规则的,我就不介绍了)。
所以不同的平台不同的编译器要不同的对待。以上算是上次的不足补充吧。
下面来看看数组:
test.c例子:
复制代码 代码如下:

void hello1()
{
    int a[3]={1,2,3};
        int b=a[1];
}
void hello2()
{
    int a[3]={1,2,3};
    int b=*(a+1);
}
void hello3()
{
    int a[3]={1,2,3};
    int b=1[a]; //这也对?
}

如果看的够仔细的话,三个函数没什么不同就是对数组a[1]的不同(当然函数名除外).
gcc -S test.c 后:
复制代码 代码如下:

.file    "test.c"
    .data
    .align 4
LC0:
    .long    1
    .long    2
    .long    3
    .text
    .globl    _hello1
    .def    _hello1;    .scl    2;    .type    32;    .endef
_hello1:
    pushl    %ebp
    movl    %esp, %ebp
    pushl    %edi
    pushl    %esi
    pushl    %ebx
    subl    $16, %esp
    leal    -28(%ebp), %edx
    movl    $LC0, %ebx
    movl    $3, %eax
    movl    %edx, %edi
    movl    %ebx, %esi
    movl    %eax, %ecx
    rep movsl
    movl    -24(%ebp), %eax
    movl    %eax, -16(%ebp)
    addl    $16, %esp
    popl    %ebx
    popl    %esi
    popl    %edi
    popl    %ebp
    ret
    .globl    _hello2
    .def    _hello2;    .scl    2;    .type    32;    .endef
_hello2:
    pushl    %ebp
    movl    %esp, %ebp
    pushl    %edi
    pushl    %esi
    pushl    %ebx
    subl    $16, %esp
    leal    -28(%ebp), %edx
    movl    $LC0, %ebx
    movl    $3, %eax
    movl    %edx, %edi
    movl    %ebx, %esi
    movl    %eax, %ecx
    rep movsl
    leal    -28(%ebp), %eax
    movl    4(%eax), %eax
    movl    %eax, -16(%ebp)
    addl    $16, %esp
    popl    %ebx
    popl    %esi
    popl    %edi
    popl    %ebp
    ret
    .globl    _hello3
    .def    _hello3;    .scl    2;    .type    32;    .endef
_hello3:
    pushl    %ebp
    movl    %esp, %ebp
    pushl    %edi
    pushl    %esi
    pushl    %ebx
    subl    $16, %esp
    leal    -28(%ebp), %edx
    movl    $LC0, %ebx
    movl    $3, %eax
    movl    %edx, %edi
    movl    %ebx, %esi
    movl    %eax, %ecx
    rep movsl
    movl    -24(%ebp), %eax
    movl    %eax, -16(%ebp)
    addl    $16, %esp
    popl    %ebx
    popl    %esi
    popl    %edi
    popl    %ebp
    ret

只要看红色的行,我们可以看到25-27行与74-76行一样,说明hello1与hello3没什么不同,
效率一样。而49-52行比他们多了一行,所以*(a+1)比a[1]和1[a]要低一点。
但是我们看下面的例子。
test1.c与test2.c:
复制代码 代码如下:

//1--------------
#include <stdlib.h>
void hello()
{
    int *a=(int*)malloc(sizeof(int)*3);
    int b=*(a+1);
    free(a);
}
 //2--------------
#include <stdlib.h>
void hello()
{
    int *a=(int*)malloc(sizeof(int)*3);
    int b=a[1];
    free(a);
}

汇编后完全一样:
复制代码 代码如下:

.file    "main.c"
    .text
    .globl    _hello
    .def    _hello;    .scl    2;    .type    32;    .endef
_hello:
    pushl    %ebp
    movl    %esp, %ebp
    subl    $40, %esp
    movl    $12, (%esp)
    call    _malloc
    movl    %eax, -12(%ebp)
    movl    -12(%ebp), %eax
    movl    4(%eax), %eax
    movl    %eax, -16(%ebp)
    leave
    ret
    .def    _malloc;    .scl    2;    .type    32;    .endef

所以在堆中使用*(a+n)与a[n]没什么不同,只用在栈中才会有所不同。
学习汇编不是必要,但是它可以让我们知道效率。

相关文章

  • C语言实现常见进制转换的示例代码

    C语言实现常见进制转换的示例代码

    生活中最常见的进制是十进制,而有一类编程题会要求将十进制转换为其他进制,本文将主要讲述C语言中常见的几类进制转换问题,希望对大家有所帮助
    2023-04-04
  • C语言中的运算符优先级和结合性一览表

    C语言中的运算符优先级和结合性一览表

    这篇文章主要介绍了C语言中的运算符优先级和结合性一览表,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02
  • 详解C++中的一维数组和二维数组

    详解C++中的一维数组和二维数组

    这篇文章主要介绍了详解C++中的一维数组和二维数组,是C语言入门学习中的基础知识,需要的朋友可以参考下
    2015-09-09
  • c 调用python出现异常的原因分析

    c 调用python出现异常的原因分析

    本篇文章是对使用c语言调用python出现异常的原因进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • C++多线程互斥锁和条件变量的详解

    C++多线程互斥锁和条件变量的详解

    这篇文章主要为大家详细介绍了C++多线程互斥锁和条件变量,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-03-03
  • C++中关于多态实现和使用方法

    C++中关于多态实现和使用方法

    这篇文章主要介绍了C++中关于多态实现和使用方法,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-07-07
  • 神奇的c/c++小游戏((提高你的编程兴趣)

    神奇的c/c++小游戏((提高你的编程兴趣)

    本文通过c/c++编写小游戏,可以提高新手们的编程兴趣,接下来我们一起来看看吧
    2021-08-08
  • C语言实现学生档案管理系统

    C语言实现学生档案管理系统

    这篇文章主要为大家详细介绍了C语言实现学生档案管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-05-05
  • C语言中strcpy和strcat的使用和模拟实现

    C语言中strcpy和strcat的使用和模拟实现

    strcpy() 函数是 C语言中一个非常重要的字符串处理函数,其功能是将一个字符串复制到另一个字符串中,strcat函数可以将一个字符串拼接到另一个字符串的末尾,本文给大家介绍了C语言中strcpy和strcat的使用和模拟实现,需要的朋友可以参考下
    2024-03-03
  • C++基于字符串实现大数相乘问题的代码详解

    C++基于字符串实现大数相乘问题的代码详解

    在实际编程中,我们经常会遇到需要处理大整数的情况,由于编程语言中内置整数类型有其表示范围的限制,当需要处理的整数超出这些范围时,就不能直接使用内置类型进行计算,所以本文给大家介绍了相关的解决方法,需要的朋友可以参考下
    2025-03-03

最新评论