-
从汇编看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的参数类型在第一次碰见就绑定了类型。
容易发怒的意思就是: 别人做了蠢事, 然后我们代替他们, 表现出笨蛋的样子。—— 蔡康永