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

    添加时间:2013-6-21 点击量:

    在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的参数类型在第一次碰见就绑定了类型。

    容易发怒的意思就是: 别人做了蠢事, 然后我们代替他们, 表现出笨蛋的样子。—— 蔡康永
    分享到: