作者descent (「雄辯是銀,沉默是金」)
看板C_and_CPP
標題Re: [問題] 關於Class指標的觀念
時間Wed Aug 28 10:26:24 2013
: http://www.parashift.com/c++-faq-lite/cant-cvt-memfnptr-to-voidptr.html
: 看來無法將 void* 轉 member function pointer。
: 我用得方法其實是把 member function 當成 non member function,
: 再把 this 傳進去。
: 大概像是這樣。
這是 virtual member function 的版本, 基本原理是一樣。
env:
g++-4.6.real (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
Ubuntu/Linaro x86 32bit
virtual member function:
void (A::*p)() = &A::func;
804873f: c7 44 24 14 01 00 00 movl $0x1,0x14(%esp)
8048746: 00
8048747: c7 44 24 18 00 00 00 movl $0x0,0x18(%esp)
804874e: 0
不過我沒搞懂這兩部份是用來幹嘛的?
得請 cppgm 參加人員解惑了。
c 語言應該沒有這麼奇怪的東西吧?
#include <iostream>
#include <cstdio>
using namespace std;
struct A
{
virtual void func()
{
printf("i: %d\n", i_);
}
void inc()
{
++i_;
}
A()
{
i_=10;
}
private:
int i_;
};
int main()
{
void (A::*p)() = &A::func;
A a;
(a.*p)();
unsigned int vptr_addr = *(unsigned int *)&a;
cout << "vptr_addr:" << hex << vptr_addr << endl;
unsigned int func_addr = *(unsigned int *)vptr_addr;
cout << "func_addr:" << hex << func_addr << endl;
a.inc();
(*(void(*)(A*))(func_addr) )(&a);
A aa;
(*(void(*)(A*))(func_addr) )(&aa);
(*(void(*)(A*))(func_addr) )(&a);
(*(void(*)(A*))(func_addr) )(&aa);
return 0;
}
執行結果:
i: 10
vptr_addr:8048af8
func_addr:80489b4
i: 11
i: 10
i: 11
i: 10
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 59.125.239.51
→ Feis:可惜我電腦是 Segmentation fault (流淚) 08/28 10:37
推 LPH66:還沒玩到那裡不過我猜有一個應該是 vtable 裡的位置 08/28 11:15
Feis: 自己追比較有趣, 每個人環境都不同, 這是給同好參考用的。
ideone 執行結果:
http://ideone.com/KLP0gG
→ Feis:事實上 64-bit 環境應該都不行. 還有我猜 VC 應該不行. 08/28 12:04
→ Feis:這跟我們假定某個實作直接寫組語有異曲同工之妙. 08/28 12:07
→ Feis:編譯器的逆向工程~ 08/28 12:08
→ Feis:不過蠻有趣的. 我去研究一下~ 08/28 12:08
→ scwg:這種東西不是去找 g++ 的 ABI 文件嗎? 跟當年有人 reverse 08/28 12:20
→ scwg:engineer 我 parse 棋譜的功能一樣, 程式碼文件都有幹麼不看 08/28 12:21
ref:
http://www.agner.org/optimize/calling_conventions.pdf
http://refspecs.linux-foundation.org/cxxabi-1.83.html (g++ 好像是參考這份實作)
推 purpose:VC 跑 a.inc(); 的下行會當掉,因為他 this 一定從 ecx 抓 08/28 12:24
→ purpose:可是這程式碼是假設 this 從堆疊抓作為前提 08/28 12:24
可以加上 c call convention 試試看嗎?
也許預設使用了 fastcall convention。
※ 編輯: descent 來自: 59.125.239.46 (08/28 12:34)
推 purpose:因為這的 A::func 是成員函式,所以裡面對變數 i 的存取 08/28 12:36
→ purpose:是寫死,一定從 this (ecx),成員函式應該不能改呼叫慣例 08/28 12:37
→ Feis:LPH66: gcc 實作裡那個 0x1 應該就是 vtable 的 offset+1 08/28 13:07
→ Feis:另一個應該是存 this 的 offset. 不過不確定. 要查一下 08/28 13:12
推 LPH66:>descent: VC 的話對非靜態成員函式使用的是 thiscall 08/28 13:16
→ LPH66:呃, 發覺 purpose 解釋完了 XD 08/28 13:17