看板 C_and_CPP 關於我們 聯絡資訊
※ 引述《littleshan (我要加入劍道社!)》之銘言: : → GNUGCC:看來各位好像不太能理解其中的道理,各位要記得,記憶體位址 08/26 20:02 : → GNUGCC:永遠都是「無號數整數型態」,float 與 double 是屬於實數型 08/26 20:03 : struct A { : void func() {} : }; : void (A::*p) = &A::func; : cout << (unsigned long)p << endl; : VC++ 2012 編譯結果: : hello.cpp(12) : error C2440: '型別轉換' : 無法由 'void (__thiscall : main::A::* )(void)' 轉換為 'unsigned long' : 沒有可以進行此轉換的內容 : 啊不是說都無號整數?為什麼轉不過去啊? : 不然轉指標好了 : cout << (int*)p << endl; 終於知道在討論什麼了。 指標就是指標, 我看不懂 (int*)p 要預期得到什麼? 因為應該不會有人想要看 A::func() 前 4 byte (32bit environment), 這並沒有什麼意義。而且語法也不支援這樣的用法, 我還蠻驚訝的, 我一直以為 reinterpret_cast 什麼都能轉, 結果踢到鐵板。 不過可以轉 void*, 再來就隨便人轉了。 但如果要得到 p (A::func() 的位址)的位址的話, 可以使用這樣的方法: #include <cstdio> using namespace std; int main() { struct A { void func() {} }; void (A::*p)() = &A::func; unsigned int addr = *((unsigned int*)&p); #if 1 printf("p: %p\n", p); printf("addr: %x\n", addr); #endif return 0; } objdump 0804856e <_ZZ4mainEN1A4funcEv>: 804856e: 55 push %ebp 804856f: 89 e5 mov %esp,%ebp 8048571: 5d pop %ebp 8048572: c3 ret descent@debian-vm:tmp$ c++filt _ZZ4mainEN1A4funcEv main::A::func() descent@debian-vm:tmp$ ./c p: 0x804856e addr: 804856e env: debian/x86 32 bit 環境 我猜 printf 應該也是類似的作法, 才能正確印出 A::func() address。 : VC++ 2012 編譯結果: : hello.cpp(12) : error C2440: '型別轉換' : 無法由 'void (__thiscall : main::A::* )(void)' 轉換為 'int*' : 沒有可以進行此轉換的內容 : 啊不是說實作上可行嗎? : 我試了一堆 compiler 都不給我過啊! : 好啦我還沒測 VC6,搞不好這個特異的 compiler 還真的能編 : → a27417332:還蠻好奇有那些機器的記憶體位址是違反無號正整數? 08/26 21:12 : → a27417332:總覺得目前的眼界還是太小XDlll感覺有好多不可思議的事 08/26 21:13 這個我還是沒搞懂。 : 上面那個例子就是了 : 不用什麼特別的機器 : 你現在在用的電腦也一樣編不過 : → GNUGCC:記憶體位址對任何機器來說都是屬於連續的位址編號,並不會有 08/26 21:24 : → GNUGCC:所謂的違反問題,就好像住家地址不可能以自已的姓名代表一樣 08/26 21:25 : 還連續編號勒 : 告訴我上面的 p 到底是幾號啊! -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 111.184.185.55 ※ 編輯: descent 來自: 111.184.185.55 (08/27 21:00)
elenya:不要拘泥於"無號正整數"這個名詞,把定址空間想成有好幾個異 08/27 21:04
elenya:次元就懂了... (天音: 這樣會懂才有鬼) 08/27 21:04
a27417332:不懂+1 QQ 08/27 21:59
purincess:樓上這樣設計MMU的硬體實作&軟體介面的人都是鬼了啊XDDD 08/27 21:59
purincess:阿 我說的是e大 08/27 21:59
elenya:樓上不用期待別人把你當正常人看了....回不去了.... XDDD 08/27 22:08
elenya:不過有一點倒是沒錯: C(C++)故意把各architecture不同的 08/27 22:09
elenya:定址問題隱藏起來,簡化成指標概念,我們何苦非要去戳破這個 08/27 22:10
elenya:美麗的幻象....不懂就不懂吧, 高階語言就是做這個用途.... 08/27 22:11
purpose:也對,可以用 &p 來讀取。之前想直接對 p 轉型一直被擋住 08/27 22:14
Feis:那你轉回去看看? 有辦法呼叫? 08/27 22:26
#include <cstdio> using namespace std; struct A { void func() { printf("123\n"); } }; typedef void (A::*MF)(); int main() { void (A::*p)() = &A::func; A a; (a.*p)(); unsigned int addr = *((unsigned int*)&p); (*(void(*)())(addr) )(); #if 1 printf("p: %p\n", p); printf("addr: %x\n", addr); #endif return 0; } 執行結果: descent@debian-vm:tmp$ ./c 123 123 p: 0x804861a addr: 804861a 是可以執行的。 ※ 編輯: descent 來自: 111.184.185.55 (08/27 22:46)
Feis:哇. A 去哪了? 好酷喔 08/27 22:48
Feis:可以幫我 "轉回來" 嗎? 08/27 22:51
descent:你的意思是要轉回 member function pointer 嗎? 08/27 22:51
Feis:當然阿. 不是很合理嗎 Q_Q 08/27 22:52
descent:我以為只要能執行就好, member function pointer 08/27 22:53
descent:的版本我不確定可以成功 08/27 22:54
Feis:那如果 64-bit 整數塞到 32-bit 整數就印不出來嗎? 08/27 22:54
Feis:其實我也不是很懂. 討論一下 08/27 22:55
littleshan:如果p指向virtual function,這樣轉過去再轉回來得到1 08/27 22:59
littleshan:光靠這個數字1你是沒辦法呼叫到正確的function 08/27 23:00
littleshan:也就是說 你這樣的轉型法會造成資料遺失 08/27 23:00
descent:virtual function 牽扯太多, 還得多研究一下。 08/27 23:06
※ 編輯: descent 來自: 111.184.185.55 (08/27 23:10)