我在這篇回應過一些想法, 不過基本上是錯誤的。
Why am I having trouble taking the address of a C++ function?
Short answer: if you’re trying to store it into (or pass it as) a pointer-to-function, then that’s the problem — this is a corollary to the previous FAQ.
Long answer: In C++, member functions have an implicit parameter which points to the object (the
this
pointer inside the member function). Normal C functions can be thought of as having a different calling convention from member functions, so the types of their pointers (pointer-to-member-function vs pointer-to-function) are different and incompatible. C++ introduces a new type of pointer, called a pointer-to-member, which can be invoked only by providing an object.
NOTE: do not attempt to “cast” a pointer-to-member-function into a pointer-to-function; the result is undefined and probably disastrous. E.g., a pointer-to-member-function is not required to contain the machine address of the appropriate function. As was said in the last example, if you have a pointer to a regular C function, use either a top-level (non-member) function, or a
上述藍色文字在說, 將 member function pointer 轉成一般 pointer 是不可行的, 雖然我做了以上的測試, 將 member function pointer 轉成 non-member function pointer 之後, 再去執行, 看起來沒什麼問題, 但直到我使用 cfront 查看 member function pointer 實作之後, 我才真正理解為什麼這樣看起來可以運作的程式碼, 其實是錯誤的, 請不要這麼做。static
(class) member function.h1.C L40 被轉成 h1..c L818
一個 member function pointer 事實上並不是指標, 而是一個結構, 參考 list 1. L017 struct __mptr, 其中有 d, i, f, 3 個欄位, 而 f 才是用來指向 member function。mf1__1AFv 就是
void A::mf1()
當使用一個 member function pointer 變數時, 其實操作的不僅僅是指標 (是 struct __mptr), 裡頭還有額外的 d, i 2 個欄位, 所以用
42 uintptr_t addr = *((uintptr_t*)&mf); 43 (*(void(*)(A *))(addr) )(&a);將一個 member function pointer 轉成一個指向 non-member function pointer, 其實並不是指標互轉, 而是把一個 struct, 裡頭有 d, i, f, 轉成一個指標, 這樣當然是不可能會正確的。
上述的語法先把 member function pointer 轉成一個整數, 再轉成 non-member function pointer 去執行。
H1.C L44 (a.*mf)(); 被轉成以下 2 行, 類似上方程式碼的轉型動作。
821 __1addr = ((*(((uintptr_t *)(& __1mf )))));
822 ((*(((void (*)(struct A *))__1addr ))))( & __1a ) ;__1mf )))));
這僅僅是 cfront 的實作方式, 不同編譯器可能會有不同的實作方式。
h1.C L47 印出這個 member function pointer 大小時, 其實是印出 struct __mptr {short d; short i; __vptp f; }; 的大小, 在我的平台上, 是 16 byte。
沒有留言:
張貼留言
使用 google 的 reCAPTCHA 驗證碼, 總算可以輕鬆留言了。
我實在受不了 spam 了, 又不想讓大家的眼睛花掉, 只好放棄匿名留言。這是沒辦法中的辦法了。留言的朋友需要有 google 帳號。