Re: [問題] 關於Class指標的觀念

看板C_and_CPP (C/C++)作者 (「雄辯是銀,沉默是金」)時間11年前 (2013/08/27 20:48), 編輯推噓2(2021)
留言23則, 7人參與, 最新討論串4/19 (看更多)
※ 引述《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)

08/27 21:04, , 1F
不要拘泥於"無號正整數"這個名詞,把定址空間想成有好幾個異
08/27 21:04, 1F

08/27 21:04, , 2F
次元就懂了... (天音: 這樣會懂才有鬼)
08/27 21:04, 2F

08/27 21:59, , 3F
不懂+1 QQ
08/27 21:59, 3F

08/27 21:59, , 4F
樓上這樣設計MMU的硬體實作&軟體介面的人都是鬼了啊XDDD
08/27 21:59, 4F

08/27 21:59, , 5F
阿 我說的是e大
08/27 21:59, 5F

08/27 22:08, , 6F
樓上不用期待別人把你當正常人看了....回不去了.... XDDD
08/27 22:08, 6F

08/27 22:09, , 7F
不過有一點倒是沒錯: C(C++)故意把各architecture不同的
08/27 22:09, 7F

08/27 22:10, , 8F
定址問題隱藏起來,簡化成指標概念,我們何苦非要去戳破這個
08/27 22:10, 8F

08/27 22:11, , 9F
美麗的幻象....不懂就不懂吧, 高階語言就是做這個用途....
08/27 22:11, 9F

08/27 22:14, , 10F
也對,可以用 &p 來讀取。之前想直接對 p 轉型一直被擋住
08/27 22:14, 10F

08/27 22:26, , 11F
那你轉回去看看? 有辦法呼叫?
08/27 22:26, 11F
#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)

08/27 22:48, , 12F
哇. A 去哪了? 好酷喔
08/27 22:48, 12F

08/27 22:51, , 13F
可以幫我 "轉回來" 嗎?
08/27 22:51, 13F

08/27 22:51, , 14F
你的意思是要轉回 member function pointer 嗎?
08/27 22:51, 14F

08/27 22:52, , 15F
當然阿. 不是很合理嗎 Q_Q
08/27 22:52, 15F

08/27 22:53, , 16F
我以為只要能執行就好, member function pointer
08/27 22:53, 16F

08/27 22:54, , 17F
的版本我不確定可以成功
08/27 22:54, 17F

08/27 22:54, , 18F
那如果 64-bit 整數塞到 32-bit 整數就印不出來嗎?
08/27 22:54, 18F

08/27 22:55, , 19F
其實我也不是很懂. 討論一下
08/27 22:55, 19F

08/27 22:59, , 20F
如果p指向virtual function,這樣轉過去再轉回來得到1
08/27 22:59, 20F

08/27 23:00, , 21F
光靠這個數字1你是沒辦法呼叫到正確的function
08/27 23:00, 21F

08/27 23:00, , 22F
也就是說 你這樣的轉型法會造成資料遺失
08/27 23:00, 22F

08/27 23:06, , 23F
virtual function 牽扯太多, 還得多研究一下。
08/27 23:06, 23F
※ 編輯: descent 來自: 111.184.185.55 (08/27 23:10)
文章代碼(AID): #1I7A07WV (C_and_CPP)
討論串 (同標題文章)
文章代碼(AID): #1I7A07WV (C_and_CPP)