zoukankan      html  css  js  c++  java
  • C++/C函数的调用规范

    先看一个代码

    void myfun(int i, int ii)
    {
        cout << i << "    " << ii << endl;
    }
    void main()
    {
        int b = 3;
        int arr[] = {6,7,8,9,10};
        int *ptr = arr;
        *(ptr++) += 123;
        printf("%d\t%d\n", *ptr, *++ptr);
        int i = 10;
        myfun(i, ++i);
    }

    VS2008输出:

    0510

    函数的调用规范

          函数的调用规范,也称为调用约定(Calling convention)。函数的调用规范决定了函数调用时,实参压栈、退栈及堆栈释放方式,以及函数名改编(Name Mangling)的方案,也即命名规范。

          Windows环境下常用的调用规范有:

         1)__cdecl:这是C/C++函数默认的调用规范,参数从右向左依次传递,压入堆栈,由调用函数负责堆栈的清退。这种方式适用于传递个数可变的参数给被调用函数,因为只有调用函数才知道它传递了多少个参数给被调函数。如printf函数。

         2)__stdcall:参数从右向左依次传递,并压入堆栈,由被调用函数清退堆栈。当函数有可变个数参数,自动转化为__cdecl调用规范。

         3)__thiscall:这是C++非静态成员函数的默认调用规范,不能使用个数可变的参数。调用非静态成员函数的时候,this指针直接保存在ECX寄存器中,不入栈。其他方面同__stdcall。

         4)__fastcall

          凡是接口函数都必须显示指定其调用规范,除非接口函数是类的非静态成员函数。

    关于结果的解释

         据说此题是华为的笔试题。但可能出题者也没理解此种的奥秘,而只知道结果。关于函数调用的参数求值顺序,语言实现标准是未定义的。之所以出现如图所示的结果,不是由函数的调用规范决定的(从右向左对参数压栈),而是由微软编译器的具体实现:参数求值按照自右向左顺序决定的。函数调用压栈压入的是表达式的计算后的值,而不是表达式本身。

        另外,如果调用myfun(i, ++i); 改为myfun(i, i++);。将输入:11     10

     

    进一步的困惑

       1: int main() 
       2: {
       3:     int i = 0;
       4:     printf( "%d, %d, %d, %d\n", i++, ++i, i, i++ );
       5:     return 0;
       6: }

         它在Visual C++ 2008的环境下编译时,输出结果为2, 3, 3, 0,在MinGW的GCC环境下编译运行时,输出结果则为2, 2, 1, 0。可见不同的编译器在实现时,对printf函数的参数进栈所作策略和抉择不同,导致了输出结果不同。结合上面关于对myfun的调用,发现即便在同一个编译器中,参数的求值顺序有时候也会不同。

         进一步学习,请参考卡http://fairymemory.net/2010/01/02/c语言函数压栈求值顺序/

  • 相关阅读:
    ZipOutputStream SharpZipLib 插件加密无法解密
    Bootstrap可视化页面布局
    Centos7中加载验证码图片报错
    Centos7中安装多版本dotnet core sdk
    NetCore中使用MySql操作数据库时发生异常
    NetCore写属性过滤时遇到的AutoFac注入的问题
    微信小程序采坑记
    PC共享网络,非软件
    hibernate HQL —— ReflectHelper.java:343
    hibernate SQL聚合查询
  • 原文地址:https://www.cnblogs.com/younes/p/1732071.html
Copyright © 2011-2022 走看看