作者LPH66 (f0VMRgEBA)
看板C_and_CPP
標題Re: [問題] 關於Class指標的觀念
時間Sun Sep 8 01:12:27 2013
: → GNUGCC:看完 descent 大大公布輸出結果不知有何感想? 09/07 23:09
: 推 LPH66:咦, 我們問的一直都是 G 兄您的感想... 09/07 23:14
: → LPH66:問 G 兄您在看到這個跟您之前的主張相矛盾的結果的感想... 09/07 23:15
: → GNUGCC:此話怎說?為何會覺得我主張相矛盾? 09/07 23:46
: 推 LPH66:您主張「指標內容是一個標示記憶體某處位址的整數」對吧? 09/08 00:11
: → LPH66:那 descent 的結果(或我在前篇推文貼的程式)正反駁了這主張 09/08 00:11
: → GNUGCC:我在前面已說過,各位只是看到包裝後的結果,但實際上編譯器 09/08 00:32
: → GNUGCC:還是把記憶體位址儲存在指標內,如果您反駁這項理論,那就請 09/08 00:33
: → GNUGCC:您說說反對的理由是? 09/08 00:33
好, 那我就再貼一次我的程式
http://ideone.com/jBEPDT
來詳細講一下這支程式裡面各個東西的用途是什麼
inspect_t<T> 這個結構裡儲存了一個指向某個型態 T 的指標
中間的 operator << 則是將 inspect_t<T> 這個結構裡所儲存的指標
其指向的東西的內容逐 byte 地列印出來
寫 basic_ostream<C,R> 只是我個人的惡趣味而已 把它換成 ostream 也並無不可
由於下面的程式將會只使用到 T* 是一個物件指標的狀況
因此在此進行 static_cast<void *> 是完全沒有問題的
根據 C++ 標準 4.10p2 將一個非空物件指標轉型成 void * 時
此 void * 將指向該物件的最開頭位址
又根據 C++ 標準 5.2.9p7 4.10p2 所述的轉換在不牽扯空指標的狀況下
是可以由 static_cast<> 反轉的
也就是說 接下來的 static_cast<char *> 確實轉換成了一個指向該處的字元指標
講這麼一大篇是要說明 operator << 裡面的程式所印出的東西
確實是這個指標所指向的記憶體位置當中所儲存的每個位元組的內容
並沒有經過編譯器自動轉型之類的「包裝」而破壞了其內容
main 的前數行是為了印證這個 operator << 確實是在執行我所說的功能
可以看到當我印出 inspect(&i) 及 inspect(&d) 時它確實印出了這兩個變數的內容
inspect(&p) 則是對照組 一個普通的指標
inspect(&fp) 也能算對照組 這是一個普通的函式指標
這裡要說明一下的是我並沒有去直接把函式指標丟來丟去
而是丟了一個「『型態為函式指標的變數』的位址」過去印出來而已
接下來的 ffp mfp cfp 則是這支程式的重點
根據上面所述 81 行所印出的確實是 cfp 這個 (成員函式) 指標的內容物
這時它的內容是 &Child::three
由輸出可以看到它是 8 個位元組的 01 00 00 00 04 00 00 00
這個結果顯然並不是一個函式位置
這可以跟 &fp 的狀況對照 在那裡它 (看起來在這個實作上) 是一個記憶體位址
而 (看起來在這個實作上) 記憶體位址的大小是 4 個位元組
那如果「指標內容就是記憶體位址」的話
究竟這 8 個位元組之中哪 4 個位元組是記憶體位址呢?
這又可以跟 75 行的 &Mother::three 對照
那裡的輸出結果是 8 個位元組的 01 00 00 00 00 00 00 00
於是這裡也有一個很有趣的現象: 明明兩個指標是同一個函式但其內容物卻是不同的
(實際進行呼叫的話這兩個指標確實可以呼叫到同一個函式)
這也不是「指標內容就是記憶體位址」這個主張可以解釋的
(明明是同一個函式為什麼這所謂的記憶體位址竟然有兩個值?)
再來 89 行又提出了一個更加有趣的現象
當我將 &Child::three 賦值給 mfp 後 mfp 的內容竟跟 75 行的結果相同
同樣是 &Child::three 又得到不同內容
這仍然不是「指標內容就是記憶體位址」可以解釋的
這樣子算不算是反駁了「指標內容就是記憶體位址」這個主張了呢?
--
LPH [acronym]
= Let Program Heal us
-- New Uncyclopedian Dictionary, Minmei Publishing Co.
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 114.41.7.174
→ LPH66:....真是的, 我明明打算這週末拿來趕 cppgm PA6 的 09/08 01:18
→ LPH66:結果卻來貼了這麼一篇文 (遠目) 09/08 01:18
→ GNUGCC:LPH66 大大,您的這一行 : 09/08 01:32
→ GNUGCC:operator <<() 的輸出在列印 ptr 指標內容...請問這樣做的 09/08 01:35
→ GNUGCC:意義是? 09/08 01:35
→ LPH66:不要被你的「編譯器包裝說」給反擊啊 (笑) 09/08 01:37
→ GNUGCC:我很好奇的是您希望它做什麼?就以指向類別成員函式的指標來 09/08 01:41
→ GNUGCC:說的話? 09/08 01:41
→ GNUGCC:還有就是您的 double 資料也是用它來輸出,這個意義是什麼呢 09/08 01:45
→ LPH66:用意就只是如你所想要的「印出指標內容」啊 09/08 01:49
→ LPH66:印 double 什麼的只不過是個證明而已 09/08 01:49
→ GNUGCC:「印出指標內容」跟「印出指標指向的內容」,您是那一個呢? 09/08 01:51
→ GNUGCC:看起來比較像是「印出指標指向的內容」耶... 09/08 01:54
→ LPH66:是啊, 當這指標指向的內容是個指標時 09/08 02:06
→ LPH66:我就達成了「印出那個指標的內容」的目的了 09/08 02:06
→ LPH66:證據就是中間的 p = &i 及 fp = main 09/08 02:07
推 littleshan:你們還在吵啊?XD 基本上我不覺得他會認錯啦 09/08 02:15
→ littleshan:所以這串討論能讓其它板友知道指標不一定能亂轉 就夠了 09/08 02:16
→ LPH66:好吧, 我去趕我的 cppgm PA6 了 (溜走) 09/08 02:18
→ Feis:大家晚安! 09/08 02:19
→ GNUGCC:我在前面有說過編譯器的實作技術會有不同,LPH66 大不知道是 09/08 10:16
→ GNUGCC:用那種的編譯器導致看到了「包裝後的結果」,不過我在用 09/08 10:16
→ GNUGCC:Visual C++ 2008 以 Debug 模式啟動可以很清楚看到函式位址 09/08 10:18
→ GNUGCC:,相信這方面 descent 大也有看過,並且也用了特殊的轉換方式 09/08 10:21
→ GNUGCC:取得位址並可呼叫到該函式,即然有部份人覺得指標可能不是存 09/08 10:22
→ GNUGCC:位址那也無仿,必竟這個是編譯器的職責跟使用者無直接關連, 09/08 10:24
→ GNUGCC:因為我在前面也說過,「不管編譯器實作技術是什麼,都不會影 09/08 10:25
→ GNUGCC:響程式執行結果」. 09/08 10:25
→ Feis:函式有位址當然合理, 只是跟指標只存函式位址是不一樣的 09/08 10:38
→ Feis:d 大也證明了成員函式指標存的不一定也不只是函式位址 09/08 10:41
→ GNUGCC:F 大可以用 Debug 模式啟動作細部觀察可以發現不一樣的東西 09/08 10:41
→ Feis:什麼不一樣的東西? 跟你的論述有關係嗎? 09/08 10:43
→ GNUGCC:當然有關係,您看了就知道. 09/08 10:45
→ Feis:我看不到什麼我不知道的阿? @@ 還是 2008 有特異功能! 09/08 10:46
→ GNUGCC:好吧,那就看得懂的人就學到了一門課,看不懂的人也無仿,只要 09/08 13:47
→ GNUGCC:編譯器不要看不懂就好了,這部份必竟還是留給系統程式設計的 09/08 13:48
→ GNUGCC:人去理解才是適合的門檻,有興趣的人可以自行研究. 09/08 13:49