• 从汇编看c++内联函数评估求值


    在c++中,一个inline函数实体,在整个class 声明未被完全看到之前,是不会被评估求值的,也就是说,对于类里面内联的成员函数本身的分析,要等到class的声明完全结束之后才开始。
    下面试c++源码:

    extern int x;//外部声明的x
    
    class X {
    public:
        float getX() const {
            return x;//x绑定的是哪个?
        }
    private:
        float x;//类自身的成员变量x
    };
    
    int main() {
       X xObj;
       float x;
       x = xObj.getX();
    }

    依据上面的规则,内联函数getX绑定的将会是成员变量x(float型)
    下面我们只看成员函数getX的汇编码:

    ?getX@X@@QBEMXZ PROC                    ; X::getX, COMDAT
    ; _this$ = ecx
    
    ; 5    :     float getX() const {
    
        push    ebp
        mov    ebp, esp
        push    ecx;压栈到的目的是为了保存对象xObj的首地址(即this指针)预留空间
        mov    DWORD PTR _this$[ebp], ecx;寄存器ecx中保留xObj对象首地址,存放到刚才分配的空间
    
    ; 6    :         return x;
    
        mov    eax, DWORD PTR _this$[ebp];将对象xObj对象首地址给eax寄存器
        fld    DWORD PTR [eax];将对象首地址处内存内容写入到浮点数寄存器ST(0)中,作为返回值 也就是将成员变量x的值返回
                           ;可以看到,x确实绑定的是成员变量
    
    ; 7    :     }
    
        mov    esp, ebp
        pop    ebp
        ret    0
    ?getX@X@@QBEMXZ ENDP


    但是,这种规则对于成员函数的参数却不是这样。
    下面是c++源码:

    typedef int length;//全局
    
    class X {
    public:
        void setI(length x)  {//length是什么类型?
            i = x;
        }
    private:
        typedef float length;//类成员
        length i;
    };
    
    int main() {
       X xObj;
       xObj.setI(1.1);
    }

    下面通过汇编码看成员变量i和成员函数setI的参数x到底是什么类型
    下面是mian函数汇编码:

    ; 13   : int main() {
    
        push    ebp
        mov    ebp, esp
        push    ecx;压栈寄存器ecx的目的,是为了为对象xObj预留4byte空间
                   ;这里没有调用xObj默认构造器是因为编译器没有必要为其提供非无用的默认构造器
    
    ; 14   :    X xObj;
    ; 15   :    xObj.setI(1.1);
    
        push    1;将1压栈作为参数传递(虽然传递的是浮点数1.1,但是这里将参数截取为整型,说明参数length确实为int)
        lea    ecx, DWORD PTR _xObj$[ebp];将对象xObj的首地址给寄存器ecx,作为隐含参数传递给成员函数setI
        call    ?setI@X@@QAEXH@Z            ; 调用setI
    
    ; 16   : }
    
        xor    eax, eax
        mov    esp, ebp
        pop    ebp
        ret    0
    _main    ENDP

    下面是setI函数的汇编码:

    ?setI@X@@QAEXH@Z PROC                    ; X::setI, COMDAT
    ; _this$ = ecx
    
    ; 5    :     void setI(length x)  {//length是什么类型?
    
        push    ebp
        mov    ebp, esp
        push    ecx;压栈寄存器ecx是为保留xObj对象的首地址预留空间
        mov    DWORD PTR _this$[ebp], ecx;寄存器ecx中存放对象xObj首地址,存放到刚才预留的空间
    
    ; 6    :         i = x;
    
        fild    DWORD PTR _x$[ebp];将参数x(int 型)放入浮点数寄存器ST(0)中, 这条指令专门将整型压入浮点寄存器
        mov    eax, DWORD PTR _this$[ebp];将对象首地址给寄存器eax
        fstp    DWORD PTR [eax];将浮点数寄存器ST(0)的内容给对象首地址存内存,即给成员变量i赋值(说明i是浮点型)
    
    ; 7    :     }
    
        mov    esp, ebp
        pop    ebp
        ret    4
    ?setI@X@@QAEXH@Z ENDP

    通过汇编码可以看到,成员函数setI的参数类型在第一次遇见就绑定了类型。

  • 相关阅读:
    如何快速转载CSDN及博客园中的博客
    Ubuntu18.04连不网 报"有线连接未托管"
    Ubuntu18.04的网络配置
    vim基本操作
    Git更新远程仓库代码到本地(转)
    POJ 3253 Fence Repair
    POJ 2503 Babelfish
    POJ 2002 Squares
    POJ 1840 Eqs
    POJ 3274 Gold Balanced Lineup
  • 原文地址:https://www.cnblogs.com/chaoguo1234/p/3149017.html
Copyright © 2020-2023  润新知