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语言函数压栈求值顺序/

  • 相关阅读:
    各种品牌电脑进入主板BIOS的方法(快捷键,按键)
    安装Oracle9i,遇到“File not found D: \oracle\ora92\ocs4j\admin\OCS4J.properties”
    关于远程桌面出现:“由于数据加密错误,这个会话将结束。请重新连接到远程计算机。”
    定时开关机
    Unix(Solaris) 常用基本命令和用户管理命令
    安装oracle9i时碰到缺少或无效口令提示
    ActiveX开发心得(转)
    oracle usermaneged recovery(三)
    用js实现改变随意改变div属性style的名称和值的结果
    Android_adb.exe的问题整理
  • 原文地址:https://www.cnblogs.com/younes/p/1732071.html
Copyright © 2011-2022 走看看