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

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]没什么不同,只用在栈中才会有所不同。
学习汇编不是必要,但是它可以让我们知道效率。

(0)

相关推荐

  • C/C++函数参数传递机制详解及实例

    C/C++函数参数传递机制详解及实例 概要: C/C++的基本参数传递机制有两种:值传递和引用传递,我们分别来看一下这两种的区别. (1)值传递过程中,需在堆栈中开辟内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本.值传递的特点是被调函数对形参的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值. (2)引用传递过程中,被调函数的形参虽然也作为局部变量在堆栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址.被调函数对形参的任何操作都被处理成间接寻址,

  • 浅析c/c++中函数的参数传递

    下面来看一段代码,看看三种传递方式产生的结果. 复制代码 代码如下: #include <cstdlib>#include <iostream>using namespace std;void change1(int n){     cout << "值传递--函数操作地址" << &n << endl;     n ++;}void change2(int &n){     cout << &qu

  • C语言中的参数传递机制详解

    C中的参数传递 本文尝试讨论下C中实参与形参的关系,即参数传递的问题. C语言的参数传递 值传递 首先看下列代码: #include <stdio.h> int main(){ int n = 1; printf("实参n的值:%d,地址:%#x\n", n, &n); void change(int i);//函数声明 change(n); printf("函数调用后实参n的值:%d,地址:%#x\n", n, &n); return

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

    mac下clang编译后函数的参数先保存在寄存器中(以一定的规则保存),然后在函数中压入栈里,以待后用.例如上篇例子,红色部分: 复制代码 代码如下: .global _decToBin _decToBin:     pushq     %rbp     movq    %rsp,%rbp movq     %rdi,-8(%rbp) #第一个参数,保存在rdi中     movq     %rsi,-16(%rbp) #第二个参数,保存在rsi中 movq    -8(%rbp),%rax  

  • Python字符串和文件操作常用函数分析

    本文实例分析了Python字符串和文件操作常用函数.分享给大家供大家参考.具体如下: # -*- coding: UTF-8 -*- ''' Created on 2010-12-27 @author: sumory ''' import itertools def a_containsAnyOf_b(seq,aset): '''判断seq中是否含有aset里的一个或者多个项 seq可以是字符串或者列表 aset应该是字符串或者列表''' for item in itertools.ifilte

  • 浅谈JavaScript 函数参数传递到底是值传递还是引用传递

    在传统的观念里,都认为JavaScript函数传递的是引用传递(也称之为指针传递),也有人认为是值传递和引用传递都具备.那么JS的参数传递到底是怎么回事呢?事实上以下的演示也完全可以用于Java 首先来一个比较简单的,基本类型的传递: function add(num){ num+=10; return num; } num=10; alert(add(num)); aelrt(num); //输出20,10 对于这里的输出20,10,按照JS的官方解释就是在基本类型参数传递的时候,做了一件复制

  • Python如何调用JS文件中的函数

    Python 调用JS文件中的函数方法如下 1.安装PyExecJS第三方库 2.导入库:import execjs 3.调用JS文件中的方法 Passwd = execjs.compile(open(r"web.js").read().decode("utf-8")).call('loginHandle','steam') 语句解析,open后跟所执行的js文件位置,call后第一个单引号引起来的为所执行的js文件的某个function, 第二个单引号是前面函数的

  • PHP实现单文件、多个单文件、多文件上传函数的封装示例

    本文实例讲述了PHP实现单文件.多个单文件.多文件上传函数的封装.分享给大家供大家参考,具体如下: 表单: s.php 要在选择上传文件时能一次选择多个文件,那么就加multiple="multiple" ,还有注意下name="myFile1"和name="myFile[]"的区别,单文件.多文件上传. <!doctype html> <html> <head> <meta charset="

  • python文件和文件夹复制函数

    本文实例为大家分享了python文件和文件夹复制函数,供大家参考,具体内容如下 文件复制函数 代码和注释如下: # 文件复制函数 def copy_file(file1,file2): ''' 将文件一复制到文件二 :param file1: :param file2: :return: ''' # 首先打开源文件file1和目标文件file2 f1 = open(file1,'r') f2 = open(file2,'w') # 循环读取写入,实现文件的复制 content = f1.read

  • PHP函数参数传递的方式整理

    在调用函数时,需要向函数传递参数,被传入函数的参数称为实参,而函数定义的参数称为形参.而向函数传递参数的方式有四种,分别是值传递.引用传递.默认参数和可变长度参数. 1. 值传递 值传递是 PHP 中函数的默认传值方式,也称为"拷贝传值".顾名思义值传递的方式会将实参的值复制一份再传递给函数的形参,所以在函数中操作参数的值并不会对函数外的实参造成影响.因此如果不希望函数修改实参的值,就可以通过值传递的方式. [示例]下面定义一个简单的函数,函数有两个参数,在函数中交换参数的值. <

  • python利用os模块编写文件复制功能——copy()函数用法

    我就废话不多说了,大家还是直接看代码吧~ #文件复制 import os src_path=r'E:\Pycharm\python100题\代码' target_path=r'E:\Pycharm\python100题\123' #封装成函数 def copy_function(src,target): if os.path.isdir(src) and os.path.isdir(target): filelist=os.listdir(src) for file in filelist: p

  • Python 添加文件注释和函数注释操作

    1.文件添加方式: pycharm提供了一个在新建文件自动生成文件头注释的功能,可以实现自动生成运行环境,作者.日期等必要信息,使用比较方便,配置十分简单. #!C:\pythonCode # -*- coding: utf-8 -*- # @Time : ${DATE} ${TIME} # @Author : hlx # @File : ${NAME}.py # @Software: ${PRODUCT_NAME} 2.自动生成函数注释,包括参数和返回值.使用方法,函数定义时,直接输入三个双引

  • pycharm自动生成文件注释和函数注释

    1. 文件注释 File -> settings -> Editor -> File and Code Templates -> Python Script pycharm提供了一个在新建文件自动生成文件头注释的功能,可以实现自动生成运行环境,作者.日期等必要信息,使用比较方便,配置十分简单. 按照1-5的路径选项即可.在5中填写想要的注释. 我的模板: # -*- encoding: utf-8 -*- ''' @File : ${NAME}.py @Contact : emac

随机推荐