精华内容
下载资源
问答
  • 其实如果函数参数固定的话,比如void func(int a, int b, int c)的入栈顺序从右到左还是从左到右怎么都行,只不过在调用不定个数参数函数时使用从左到右压站就麻烦了。比如printf(“%d-%d-%d\n”,a,b,c);printf...

    其实如果函数的参数固定的话,比如void func(int a, int b, int c)的入栈顺序从右到左还是从左到右怎么都行,只不过在调用不定个数参数的函数时使用从左到右压站就麻烦了。比如printf(“%d-%d-%d\n”,a,b,c);printf的参数个数是通过第一个参数format中的%d %dx %xxxx来确定后面跟有几个实际参数的。如果入栈顺序从左到右,则应该是栈低到栈顶为:“%d-%d-%d\n”+a+b+c;当调用到函数时候,去访问他的参数,则只能访问到栈顶元素c,但是函数有需要确定有个实际参数,但是c有不是保存了format信息不知道到底有几个参数。所以从左到右就会很麻烦,于是通过从右到左额方式压栈,就能在栈顶一下子取到“%d-%d-%d\n”信息知道栈里面紧接着有多少实际参数了。然后一个一个的取就可以了。说白了从右到左的目睹就是为了解决不定参函数的取参数方便的目的的。

    展开全文
  • 参数入栈顺序 c++提供了5种参数传递标准,除了main函数传递必须用_cdecl模式,其他函数可以自己在编译器设置,默认的是_cdecl模式,即从右到左入栈 参数计算顺序 参数的入栈和计算顺序并不是一回事,c++标准并未指定...

    参数入栈顺序

    c++提供了5种参数传递标准,除了main函数传递必须用_cdecl模式,其他函数可以自己在编译器设置,默认的是_cdecl模式,即从右到左入栈

    参数计算顺序

    参数的入栈和计算顺序并不是一回事,c++标准并未指定参数的计算顺序,不同的编译器在执行f(++a,a+b)时所得的结果可能不同。

    展开全文
  • 函数参数入栈顺序,参数计算顺序以及可变参数的实现

    函数参数入栈顺序

    #include
    void foo(int x, int y, int z)
    {
            printf("x = %d at [%X]\n", x, &x);
            printf("y = %d at [%X]\n", y, &y);
            printf("z = %d at [%X]\n", z, &z);
    }
    int main(int argc, char *argv[])
    {
            foo(100, 200, 300);
            return 0;
    }

    运行结果是:
    x = 100 at […60]

    y = 200 at […64]

    z = 300 at […68]

    这是由于,C程序栈的内存生长方式是往低地址内存生长,这也说明为什么局部变量无法申请太大内存,因为栈内容有限。此外,这个例子说明,函数参数的入栈的顺序是从右往左的!。参数入栈顺序具体的还与编译器相关,涉及到C语言中调用约定所采用的方式:

    C调用约定在返回前,要作一次堆栈平衡,也就是参数入栈了多少字节,就要弹出来多少字节.这样很安全.

    有一点需要注意:stdcall调用约定如果采用了不定参数,即VARARG的话,则和C调用约定一样,要由调用者来作堆栈平衡.

    (1)_stdcall是 Pascal方式清理C方式压栈,通常用于Win32 Api中,函数采用从右到左的压栈方式,自己在退出时清空堆栈。VC将函数编译后会在函数名前面加上下划线前缀,在函数名后加上”@”和参数的字节数。 int f(void *p) –>> _f@4(在外部汇编语言里可以用这个名字引用这个函数)在WIN32 API中,只有少数几个函数,如wspintf函数是采用C调用约定,其他都是stdcall

    (2)C调用约定(即用 __cdecl关键字说明)(The C default calling convention)按从右至左的顺序压参数入栈,由调用者把参数弹出栈。对于传送参数的内存栈是由调用者来维护的(正因为如此,实现可变参数 vararg的函数(如printf)只能使用该调用约定)。另外,在函数名修饰约定方面也有所不同。 _cdecl是C和C++程序的缺省调用方式。每一个调用它的函数都包含清空堆栈的代码,所以产生的可执行文件大小会比调用_stdcall函数的大。函 数采用从右到左的压栈方式。VC将函数编译后会在函数名前面加上下划线前缀。

    (3)__fastcall调用的主 要特点就是快,因为它是通过寄存器来传送参数的(实际上,它用ECX和EDX传送前两个双字(DWORD)或更小的参数,剩下的参数仍旧自右向左压栈传 送,被调用的函数在返回前清理传送参数的内存栈),在函数名修饰约定方面,它和前两者均不同。__fastcall方式的函数采用寄存器传递参数,VC将 函数编译后会在函数名前面加上”@”前缀,在函数名后加上”@”和参数的字节数。

    (4)thiscall仅仅应用于”C++”成员函数。this指针存放于CX/ECX寄存器中,参数从右到左压。thiscall不是关键词,因此不能被程序员指定。

    (5)naked call。 当采用1-4的调用约定时,如果必要的话,进入函数时编译器会产生代码来保存ESI,EDI,EBX,EBP寄存器,退出函数时则产生代码恢复这些寄存器的内容。

    综上,其实只有PASCAL调用约定的从左到右入栈的.而且PASCAL不能使用不定参数个数,其参数个数是一定的。

    可变参数的实现

    支持可变参数的__cdecl调用其实可以理解的。C方式入栈顺序从右往左,那么在栈底的元素就是可变参数的最右边一个,我们只需要知道所有明确参数里的最左边一个参数在栈中的位置,剩下到栈底的都是可变参数了,反之如果从左往右入栈,则无法知道最右边的可变参数在栈中的位置。在具体实现中,也可观察到其中的原理,包括,需要调用者手动清栈。

    float averge(int n_values, ...)
    {
        va_list var_arg;
        // 准备访问可变参数
        va_start(var_arg, n_values);// 第一个参数是va_list变量的名字,第2个参数是省略号前最后一个有名字的参数
        // 取值
        for(::)
            sum += va_arg(var_arg, int);// 第二个参数是参数的类型
        // 完成处理可变参数,手动清栈
        va_end(var_arg);
    }

    结论很简单:如果支持可变参数的函数,那么参数进栈的顺序几乎必然是自右向左 的。并且,参数出栈也不能由函数自己完成,而应该由调用者完成。

    函数参数计算顺序

    主要想说明的是,函数的参数压栈顺序和参数计算顺序不是一个概念。一个函数带有多个参数的时,C++语言没有规定函数调用时实参的求值顺序。这个是编译器自己规定的。

    比方说int z = add(++x,x+y);不同编译器可能产生不同结果。

    转载自: http://blog.csdn.net/weichaohnu/article/details/8798581

    展开全文
  • 先给出本文参考的链接: [C/C++函数参数读取顺序 ] [关于c语言和c++中的...[C++函数参数入栈顺序]问题其实今天的学习始于这样一段代码的结果:#include <stdio.h>void foo( int x, int y, int z ){ printf( "%d

    先给出本文参考的链接:
    [C/C++函数参数读取顺序 ]
    [关于c语言和c++中的函数参数的执行顺序的问题],裘宗燕老师的讲解非常准确。尤其是对于表达式计算,表达式的副作用,都有启发性的讲解。
    [C++函数参数的入栈顺序]

    问题

    其实今天的学习始于这样一段代码的结果:

    #include <stdio.h>
    
    void foo( int x, int y, int z ){
        printf( "%d %d %d.\n", x, y, z );
    }
    
    int main( void ){
    
        int a = 10;
        foo( a++, ++a, a );
    
        return 0;
    }

    首先,按照正常的理解,参数入栈顺序从右至左,那么入栈序列应该是[ 10, 11, 11 ],最后的a = 12.此时[ z = 10, y = 11, x = 11 ],最后输出11,11,10.这是希望看到的结果。
    但是,最后的结果是11,12,12.这是怎么回事呢?

    具体的内容看讲解,我直接给结论:

    1.在将参数入栈前,编译器会先把参数的的表达式都处理掉,哪怕这些运算会改变其中某些参数的值.

    2.对于a++操作,编译器会开辟一个缓冲区来保存当前a的值,然后再对a操作,取值时是从缓冲区取,而不是直接从a的内存地址里取。

    简言之,参数在入栈前,会全部计算出结果,然后根据这个结果入栈,但是对于a++这样的操作,并不会入栈最终的结果,而是之前保存的临时结果。
    计算顺序,假设从右向左(实际上,c/c++语言本生没有定义语言的计算顺序,讨论这个计算顺序也没有意义,裘宗燕老师的观点)但是,本例中确实是从右向左。

    10
    11
    11-12
    最后的结果是
    12(保存最后更新的值)
    12(保存最后更新的值)
    11(上一次更新前的值)
    即[11,12,12]

    进一步的讨论

    1.函数参数的入栈顺序
    假设目前面临的是可变参数的情形,不知道参数的个数。如果从左向右入栈,因此要想知道首参数的值,则必须要知道参数的长度.而栈里并不知道这个长度,那么就无法通过指针偏移的方式找到首参数.

    如果使用从右到左的传参方式,栈顶看到的就是左边输入的首参数,因此,无论怎样的变长,都可以通过指针偏移的方式找到值.

    因此找到首参数是一件非常重要的事情,这是为什么?因为参数的入栈顺序是从右至左,但是参数的结合顺序是从左至右,因此如果拿不到首参数的地址,没办法开始从左至右进行结合。

    这也是为什么函数的默认参数一定要写到参数列表的右侧,因为参数的结合是从左至右,如果当实际参数的个数小于形式参数时,默认参数如果在左侧,那么先和默认参数结合,右侧的参数无法结合。但是如果默认参数在右侧,可以先和左侧参数结合,那么当参数不够时,右侧默认参数可以发挥作用。

    2.函数的计算顺序
    这个在语言里面并没有定义,而是靠编译器自己灵活处理。裘宗燕老师的讲解非常准确。


    后记

    对于参数的入栈顺序有了新的认识,为什么要从右向左。
    原因都知道,主要是为了避免变长参数列表的情形。但是具体原因,不是很清楚。早上把这个东西想明白了。

    这里之前有一个误区就是,对于变长的参数,参数入栈的时候,编译器不会记录元素个数,就是往里入栈。
    那么,我们考虑从左向右入栈。那么栈底是最后一个元素,好,那我现在问你,请给我第8个元素?你怎么得到?因为你不知道元素的个数,所以,你并不知道要出栈多少次才以到8.主要是不知道偏移,加入你知道总共的元素个数n,那么偏移地址是n-8.但是,你不知道元素的个数。所以,算不出偏移量。但是,如果是从右到左入栈,栈顶是第一个元素,那么现在第8个元素,它的偏移量是8-1,这个你是可以算出来的。所以,出栈7次就可以了。这也是为什么要从右向左入栈,因为对于变长参数而言,栈顶是第一个元素,可以算出偏移量。

    展开全文
  • C++函数参数入栈顺序

    千次阅读 2013-10-08 19:28:20
    长期以来大家都有一个疑问,C++函数参数入栈顺序倒底是怎样的呢? 经验丰富的程序员一定会说C++参数的传输顺序是从右到左的, 这一点大家不妨可以自己建立一个控制台程序,看看函数入参的栈地址,你会发现栈底是最...
  • C++ 函数参数入栈方式与调用约定

    千次阅读 2015-08-10 17:16:11
    要实现函数调用,除了要知道函数的入口地址外,还要向函数传递合适的参数。向被调函数传递参数,可以有不同的方式实现。这些方式被称为“调用规范”或“调用约定”。C/C++中常见的调用规范有__cdecl、__stdcall、__...
  • C语言中函数参数入栈顺序,到底是从右到左,还是从左到右呢? 先看一个网上的程序例子: #include void foo(int x, int y, int z) { printf("x = %d at [%X]n", x, &x); printf("y = %d at [%X]n", y, &y)...
  • 对技术执着的人,比如说我,往往对一些问题,不仅想做到“知其然”,还想做到“知其所以然”。...某天某地某人问我,C语言中函数参数入栈顺序如何?从右至左,我随口回答。为什么是从右至左呢?我终究没有给
  • 关注、星标公众号,直达精彩内容ID:技术让梦想更伟大作者:李肖遥如果大家细心的话应该知道c/c++语言函数参数入栈顺序为从右至左,那么为什么这样呢?来看看两个知识点:参数的计算顺序与压栈顺...
  • (转)C语言中函数参数压栈顺序小结先看一个小程序:#include &lt;stdio.h&gt;int f(int i, int j, int k) { printf(&quot;%d at [%X]\n%d at [%X]\n%d at [%X]\n&quot;, i, &amp;i, j, &amp...
  • 某天某地某人问我,C语言中函数参数入栈顺序如何?从右至左,我随口回答。为什么是从右至左呢?我终究没有给出合理的解释。于是,只好做了个作业,于是有了这篇小博文。#include void foo(int x, int y, i
  • 由该文章知道计算机中栈的生长方向为由高到低,及栈底为高地址,栈顶为低地址,因此函数输入参数入栈顺序可以由栈地址大小判断,地址大的先入栈,地址小的后入栈 #include void Var_Order(int x, int y, int z) ...
  • C语言中函数参数入栈顺序 先通过一个小程序来看一看: #include void foo(int x, int y, int z) { printf("x = %d at [%X]n", x, &x); printf("y = %d at [%X]n", y, &y); printf("z = %d at [%X]n", z, &z); } ...
  • C语言中函数参数入栈顺序 先通过一个小程序来看一看: #include void foo(int x, int y, int z) { printf("x = %d at [%X]n", x, &x); printf("y = %d at [%X]n", y, &y); printf("z = %d at ...
  • 基于上述分析,便可知道为什么C/C++参数入栈顺序是从右向左了——如果是从左向右压栈,第一个参数(即描述可变参数表各变量类型的那个参数)将被放在栈底,由于可变参的函数第一步就需要解析可变参数表的各参数...
  • 进一步发现,Pascal语言不支持可变长参数,而C语言支持这种特色,正是这个原因使得C语言函数参数入栈顺序为从右至左。具体原因为:C方式参数入栈顺序(从右至左)的好处就是可以动态变化参数个数。通过栈堆分析可知,...
  • C语言中函数参数入栈顺序
  • 原来一直c++开发,偶尔会遇到参数入栈顺序的问题,而c++是右侧函数先入栈.例子如下: #include using namespace std; int left(int& a) { a *= 2; cout ; return a; //10 } int right( int& a) { a +=

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 19,363
精华内容 7,745
关键字:

c++函数参数入栈顺序

c++ 订阅