看板 C_and_CPP 關於我們 聯絡資訊
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; 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: 202.39.238.242
purincess:我相信他等等會開assembler然後把call rel/call abs的 08/26 23:59
purincess:target address拿出來跟你說就是那個值... 08/26 23:59
purincess:s/assembler/assembly 08/26 23:59
littleshan:那我好心提醒一下 那個值是錯的 08/27 00:27
GNUGCC:其實這個例子滿有趣的,可以試看看這個 : 08/27 01:01
GNUGCC:cout << &A::func; 08/27 01:03
GNUGCC:會發現什麼都沒有,可以思考看看為什麼會這樣. 08/27 01:04
GNUGCC:L 大大,一個大陣列的記憶體位址是不是連續的您應該知道吧? 08/27 01:21
Feis:哈哈. G大又本末倒置了 08/27 01:28
GNUGCC:Feis : 此話怎說? 08/27 01:29
littleshan:那不是我要思考的,是你要自圓其說 08/27 01:35
littleshan:你說記憶體位址都是無號整數 但顯然不是這樣 08/27 01:35
Feis:話說是不是應該是 void (A::*p)() = &A::func; 我醉了嗎 Q_Q 08/27 01:40
不不是我醉了 今天應酬多喝了一杯 tequila shot 害我犯了這種低級錯誤
GNUGCC:L 大大,竟然您提出了問題,但您確定有思考過這個問題為什麼 08/27 01:42
GNUGCC:會發生嗎?如果不思考而直接提問想要對方自圓其說,這樣說好 08/27 01:43
啊?你在跟誰說話啊? 我當然知道答案啊!因為 p 不是單純的無號整數嘛! 至於 p 是什麼,要看 compiler 大部份的 compiler 都是採用....等一下為什麼我要跟你說這個啊? 你不是堅持 p 是無號整數嗎?我提出反例結果竟然是你要我先思考這個問題?
Feis:那G大可以說說高見嗎? 08/27 01:43
GNUGCC:像不符合事實吧? 08/27 01:44
GNUGCC:如果「知其然,並不知其所然」,這是每個人的必經之路,唯有抱 08/27 01:46
GNUGCC:著一顆學習的心態才能使自已成長. 08/27 01:46
※ 編輯: littleshan 來自: 202.39.238.242 (08/27 02:01)
Feis:所以呢? cout << &A::func 什麼都沒有又是哪招? 08/27 01:54
GNUGCC:在我的電腦上,如果要輸出「類別內的函式或是資料成員」的 08/27 02:55
GNUGCC:位址,有可能會看到不正確的結果,如果以啟動 Debug 模式,可 08/27 02:56
GNUGCC:以看到 p 的確是有位址資料,但輸出是 0 或是 1,顯然這個跟 08/27 02:57
GNUGCC:編譯器實作有關係,所以 p 並不是沒有資料,而是被編譯器隱藏 08/27 02:58
GNUGCC:起來不讓您看到,為什麼會這樣說呢?當編譯器遇到這個敘述 : 08/27 03:00
GNUGCC:void(A::*pv)(void) = &A::func; 08/27 03:04
GNUGCC:cout << pv; // 這個敘述無義意 08/27 03:05
GNUGCC:我用 Visual C++ 2008 編譯器對應策略是 : 08/27 03:06
GNUGCC:取得 func() 函式的位址,再來就是比對數值是否為 0 08/27 03:08
GNUGCC:然後接著直接輸入數字 1 08/27 03:09
GNUGCC:抱歉!是輸出數字 1 08/27 03:09
GNUGCC:我的理解是 : 因為這個數字並不是 func() 函式位址,當然 08/27 03:11
GNUGCC:編譯器也就無法讓您做所謂的「強制轉型」了. 08/27 03:12
AnyaAlstreim:「可以思考看看為什麼會這樣」 XDDDD 08/27 07:22
scwg:我是覺得啊, 小善啊, 你被 troll 得很徹底啊 XD 08/27 08:15
Feis:G 大... cout << pv 是進 cout.operator<<(bool) 吧? 08/27 08:29
Feis:而且這跟 cout << (int *) pv 的關係是什麼阿? =.= 08/27 08:31
Feis:還是G大不知為什麼會是 1. 應該不會. 是我應該思考看看.. 08/27 08:36
Feis:喔喔. 為了證明我有思考過. 關鍵字是 C++03 4.12 條 08/27 08:41
GNUGCC:我要您思考的是,為什麼遇到這個敘述即使用了「強制轉型」仍 08/27 08:56
GNUGCC:無法轉換?而不是編譯器的實作原因為何,如果今天這個 pv 是 08/27 08:57
Feis:我不用思考阿. 問題是你的答案 "是錯的" 08/27 08:57
Feis:GNUGCC: 你找個 C++ 實作, 然後出來不是 1 的來瞧瞧 08/27 08:59
Feis:沒有的話, 可以請你不要一直扯嗎 08/27 08:59
GNUGCC:指向一般資料或是函式位址,編譯器就會做轉換? 08/27 09:00
GNUGCC:我想要說的是,L 大大問的問題本身就違反了 C++ 規則,所以 08/27 09:04
GNUGCC:編譯器的對應策略就是我上面說的那樣,我說過「語意上不可行 08/27 09:06
GNUGCC:,實作上可行」的就是這個例子,您永遠看到都只是 1 而已,對 08/27 09:07
Feis:違反了 C++ 規則的哪一條?. 你要不要去思考看看 08/27 09:07
GNUGCC:編譯器來說已實作出結果了,但這會是您想要的嗎? 08/27 09:07
Feis:你的答案完全證明你還是不知道為什麼是 cout << pv 是 1. 08/27 09:08
Feis:這是 C++ 標準規定的. 喔. 你可能不知道什麼叫做標準 08/27 09:09
GNUGCC:F 大大,難道您還不知道答案嗎? 08/27 09:11
Feis:我答案關鍵字都給你了. 前輩. 08/27 09:13
GNUGCC:即然您要問我輸出結果不是 1 的例子,像這樣 : 08/27 09:15
GNUGCC:void(*A::pv)(void) = 0; 08/27 09:16
GNUGCC:cout << pv; 08/27 09:16
GNUGCC:不知道這樣清楚了嗎? 08/27 09:16
Feis:清楚什麼? 我之前答案就寫了阿. 你說的是原 po 版不一定是1 08/27 09:18
Feis:然後現在又拿一個 null pointer 救援. 真的是亂扯 08/27 09:18
Feis:那你清楚嗎? 為什麼會是 0 ? 會不會不同實作不一樣? 08/27 09:19
GNUGCC:今天這個例子來看的話,編譯器已遇到「違反 C++ 規則,原屬語 08/27 09:19
Feis:還有這是標準, 具有正確語意. 別再說是語意不可行好不 08/27 09:20
Feis:違反 C++ 規則哪一條? 前輩你找到了嗎? 08/27 09:20
GNUGCC:意上不可行,但編譯器有內定的演算法」,所以編譯器並不會出 08/27 09:21
GNUGCC:現預期結果. 08/27 09:21
Feis:這是 C++ 標準預期結果. 你行行好吧 08/27 09:22
GNUGCC:這個例子是在討論「違反 C++ 規則那一條,還是無法做強制轉 08/27 09:22
GNUGCC:型的原因?」,請 F 大大不模糊焦點了. 08/27 09:23
Feis:我只跟你討論 cout << pv 為什麼是 1 或 0 08/27 09:23
Feis:至於原 po 的已經很明顯你扯 cout << pv 救援了 08/27 09:24
Feis:是你愛模糊焦點吧 08/27 09:24
GNUGCC:呵呵...本人並沒有「救援」的想法,只是在說明事實. 08/27 09:28
Feis:你以為 cout << pv 印出來的是 pv 的值? 08/27 09:28
azureblaze:F大您真閒 08/27 09:31
Feis:我也想去吃早餐阿 08/27 09:31
GNUGCC:為何輸出 1 我在前面已說過了,請往回看記錄唷... 08/27 09:43
GNUGCC:而且 F 大大已說到答案了,就是因為「C++ 的標準」,導致 08/27 09:44
GNUGCC:L 大大的例子無法使用強制轉型,這樣夠清楚了吧? 08/27 09:45
Feis:到底哪裡清楚,是非題:cout<<p有轉型嗎 08/27 09:47
GNUGCC:所以現在是在「考我」? 08/27 09:50
Feis:因為你愛亂扯,是非題簡單多了 08/27 09:52
GNUGCC:「為何不能使用強制轉型」,與「違反 C++ 規則那一條」應該 08/27 09:52
GNUGCC:是分開討論的主題吧,F 大大請不要再模糊焦點了. 08/27 09:53
Feis:啊不然你要討論什麼,原po的問題你不知道,我的也不回 08/27 09:55
Feis:X講了一堆似是而非的 08/27 09:56
CaptainH:GNUGCC:我想要說的是,L大大問的問題本身就違反了C++規則 08/27 10:03
CaptainH:那你知道"記憶體位址是無號整數"跟本沒在c/c++規則裡嗎? 08/27 10:04
CaptainH:如果p就是無號整數, 那又有什麼理由不給轉呢? 08/27 10:07
GNUGCC:原 po 的問題我已說出答案了,至於 F 大大的問題,編譯器只是 08/27 10:14
GNUGCC:轉呼叫「能輸出 BOOL 型態數值」的函式,所以 CaptainH 大大 08/27 10:18
GNUGCC:您認為這樣編譯器會給您轉嗎? 08/27 10:19
GNUGCC:C++ 規則記錄的是語法的使用規則與文法的正確性,並不包含 08/27 10:20
Feis:Wrong answer. 好,我休息。浪費時間 08/27 10:20
GNUGCC:「電腦硬體規格」,記憶體位址為什麼要使用無號整數可以看 08/27 10:21
GNUGCC:我在其他討論區說明的. 08/27 10:22
CaptainH:既然是無號整數, 為何還要轉成bool? 08/27 10:24
CaptainH:應該這樣問,為何 &A::func 無法轉型成 int* 或 void* ? 08/27 10:28
GNUGCC:這個問題很有趣,因為這是編譯器遵循 C++ 規則所看到的結果. 08/27 10:29
CaptainH:反正只是無號整數互轉嘛~ 08/27 10:29
CaptainH:那你知道為什麼C++要這樣訂嗎? 08/27 10:29
a27417332:所以,在電腦的底層上,物件的函數的指標(?)不一定是無 08/27 10:32
a27417332:號正整數?印象中之前看C++物件模型,好像作者有提到這 08/27 10:32
a27417332:東西的編譯結果會不一樣@@但不太明確清楚意思 08/27 10:32
GNUGCC:為何 &A::func 看不到函式的位址可以往前看記錄唷... 08/27 10:33
GNUGCC:我目前能理解的是,這個可能跟本身區段的分配有關係,因為對 08/27 10:37
GNUGCC:一般的資料或是函式而言,都有明確的區段所在位置,各位要知 08/27 10:39
GNUGCC:道一個完整的程式有所謂的程式區段與資料區段跟堆疊區段,那 08/27 10:40
GNUGCC:C++ class 的資料排列方式或許跟一般資料的排列大不相同, 08/27 10:41
GNUGCC:一般的函式在程式區段,變數是在資料區段,呼叫函式的過程就 08/27 10:43
GNUGCC:因為參數的傳遞方式而決定要不要使用堆疊區段,但 C++ class 08/27 10:44
GNUGCC:是屬於「資料型態」類型的變數,編譯器或許把它放在資料區段 08/27 10:45
GNUGCC:內,但因為裡面包含了函式,編譯器絕不可能把函式也放在資料 08/27 10:46
GNUGCC:內,或許在程式區段內儲存類別的成員函式,編譯器也許可能用 08/27 10:47
a27417332:看到debugger裡面有記憶體位址的樣子,但轉不了型Orz 08/27 10:50
GNUGCC:了一個「指向程式區段」指標儲存這個函式的位址,有點類似 08/27 10:50
GNUGCC:虛擬函式的技術但不完全相同,所以應該就能理解為何 C++ 規 08/27 10:55
GNUGCC:則為何要這樣做了...這是我個人的推斷囉. 08/27 10:55
littleshan:所以咧? &A::func 到底是不是無號整數啊? 08/27 13:46
littleshan:指標的強制轉型寫法不管那一種編譯器仍會完成轉型動作 08/27 13:47
littleshan:上面那句話可是你說的吶 08/27 13:47
b98901056:這串下來學滿多的XD 不過有人好像一直跳針或鬼打牆XD 08/27 13:51
purincess:你們都不用上班的嗎 XDDDDDDD 08/27 14:05
purincess:一個大陣列的(虛擬)記憶體位址應該是連續的吧 08/27 14:05
purincess:是說user space program裡面很難碰到phy addr 08/27 14:05
GNUGCC:看前面的記錄可以知道結果唷 08/27 14:08
GNUGCC:L 大大,您可以利用下面這個敘述 : 08/27 14:11
GNUGCC:void(A::*pv)(void) = &A::func; 08/27 14:11
GNUGCC:利用 Debug 模式觀看 pv 變數值,那個記憶體位址就是 func() 08/27 14:12
GNUGCC:函式的位址,不過因為 C++ 規格的關係,編譯器把它隱藏了,只 08/27 14:13
loveme00835:不要用實作來理解一個語言的設計. 你可能一生中只碰得 08/27 14:13
GNUGCC:能透過 Debug 的方法來看到,但編譯器仍完成了轉型,但結果是 08/27 14:13
loveme00835:得到某幾種架構的CPU, 某幾個編譯器, 不代表你看到的 08/27 14:14
GNUGCC:1,這個就是編譯器內部的演算法策略. 08/27 14:14
loveme00835:就正確的, 結案. 我們根本就不該對記憶體位址有什麼偏 08/27 14:15
loveme00835:執, 它應該被當作一個門牌, 而不是一個整數 08/27 14:15
loveme00835: ↑指標 08/27 14:16
GNUGCC:板主所言甚是,但電腦硬體架構是一成不變的,並不會換了軟體 08/27 14:18
GNUGCC:而決定硬體的使用方式,我所說的「記憶體位址是連續的編號」 08/27 14:19
GNUGCC:是指作業系統看到的,但實際上會因為記憶體的管理而讓使用者 08/27 14:20
GNUGCC:覺得好像沒有連續,試想這樣的事情 : 宣告陣列的時候為什麼 08/27 14:21
GNUGCC:是用連續排列的方式而儲存,而不是跳著存呢? 08/27 14:22
GNUGCC:我們都知道,在 32 bit 作業系統下能存取的記憶體範圍是 08/27 14:28
GNUGCC:0 ~ FFFFFFFF,這個就是能證明記憶體位址是連續的最好例子, 08/27 14:29
GNUGCC:但有可能全部都給您程式使用嗎?當然不可能,不然作業系統就 08/27 14:29
GNUGCC:不需要做記憶體管理了,因為我們的程式大部份都是屬於在作業 08/27 14:31
GNUGCC:系統層次上運行,使用的權限與資源都被作業系統掌控,所以當 08/27 14:32
GNUGCC:然看不出來它裡面的秘密了. 08/27 14:33
a27417332:希望L大能把"大部分的編譯器是採用..."這段說完QQ 08/27 14:37
descent:這個例子是 member function pointer, c pointer 也有 08/27 14:50
descent:類似的東西嗎? 08/27 14:50
descent:沒看到其他例子, 很難想像不是連續整數的位址 08/27 14:51
scwg:GNUGCC 那麼喜歡 16-bit 時代的寫法, 怎麼會覺得位址是非負 08/27 15:03
scwg:整數呢? 位址明明就是 segment 和 offset 兩個數啊 08/27 15:04
Killercat:我想說的是 記憶體位置並非連續的編號,他是有空洞的 08/27 15:58
Killercat:事實上32bit下能「存取」的範圍即使非保護模式下 08/27 15:59
Killercat:也不是從0開始 也不是結束於ffffffff @@a 08/27 16:00
Killercat:也許是我對您的文字理解有誤 如果有誤請指正 08/27 16:02
Killercat:0是virtual range的起點 但是終點是7f 08/27 16:03
Killercat:實體range則不可能從0開始 前半段要保留給rom map 08/27 16:03
Killercat:所以0~ffffffff其實在兩種觀點看來都是不太正確的 08/27 16:04
purpose:http://codepad.org/v2uZTiPN 亂寫的 08/27 18:54
purpose:http://pastebin.com/NCF3nakX,上面程式寫錯,抓成 main 08/27 19:43
purpose:的位址。GCC 不會像 VC 一樣先到 00401005 後才去成員函式 08/27 19:43
purpose:抓上一層是 __builtin_return_address(0) 才對,這邊也錯 08/27 19:45
GNUGCC:K 大大,我在前面說過,記憶體存取範圍會因為作業系統使用了 08/27 19:55
GNUGCC:記憶體管理而讓使用者覺得位址好像沒有連續,前面也說到不可 08/27 19:57
GNUGCC:能全部都給自已使用,0 ~ FFFFFFFF 只是一個範圍,從那裡開始 08/27 19:58
GNUGCC:是作業系統自已決定,程式設計師只能使用作業系統給的有限範 08/27 19:59
GNUGCC:圍內使用. 08/27 20:00
GNUGCC:S 大大,即然您知道位址是 Segment 與 Offset 組成,那為什麼 08/27 20:18
descent:printf("p: %s\n", p) 就可以看到位址 08/27 20:18
descent:不知道 cout 為什麼不行 08/27 20:19
GNUGCC:不會覺得是正整數呢?可以請您說明一下嗎,謝謝 08/27 20:19
elenya:pointer應該是%p吧,%s是字串 08/27 20:22
elenya:[請問] 0100:0000 與 0000:1000 有何不同? 08/27 20:23
GNUGCC:D 大大說到重點了,各位可以想看看為什麼 printf() 函式可以 08/27 20:24
GNUGCC:看到位址? 08/27 20:24
elenya:我就知道你要直接切進DOS4GW模式 XD 08/27 20:25
Bencrie:沒想到本板還看得到 dos4gw XD 08/27 20:43
descent:elenya: 感謝更正, 是 %p 沒錯。 08/27 20:49
GNUGCC:在 16 bit 下, 0100:0000 與 0000:1000 並沒有不同,因為它 08/27 20:54
GNUGCC:們都是代表同一個實體位址,也就是 16 進位絕對位址 1000 08/27 20:56
elenya:真實模式下絕對位址沒有不同沒錯,當作word或byte address時 08/27 20:58
elenya:取到的資料相同沒錯,但位於不一樣的segment,基本上是不一樣 08/27 20:59
elenya:的long pointer,加上F000 offset一個指到10000一個是00000 08/27 21:01
elenya:不過在C&C++板討論assembly我是不是應該要自請水桶... 08/27 21:02
GNUGCC:E 大,這個問題是屬於組合語言的部份了. 08/27 21:03
GNUGCC:這個問題可以另外討論,但我要強調的是,不管是使用那一種記 08/27 21:04
GNUGCC:憶體表示法,它們永遠都是屬於「無號正整數」,其實我還滿想 08/27 21:05
GNUGCC:看用負數的方式來表示記憶體位址呢! 08/27 21:06
elenya:負數可以啦,不過用不著特別去計較它是正數還是負數 08/27 21:12
elenya:反正只討論flat model的話,比0小就算負數了,你要講無號也通 08/27 21:13
elenya:非flat model還有很多畸形architecture可以討論 08/27 21:16
elenya:我看到前排這位8051在舉手了,給我坐下,不關你的事。 08/27 21:17
GNUGCC:並非計較,只是強調觀念,而且我很好奇的是,即然存取範圍是 08/27 21:19
GNUGCC:0 ~ FFFFFFFF,那為什麼會有負數呢? 08/27 21:19
GNUGCC:難道 FFFFFFFF 可以解釋成 -1 ? 08/27 21:20
GNUGCC:而且您說的 0100:0000 與 0000:1000 位移 F000 後會不一樣, 08/27 21:25
GNUGCC:可以另外討論. 08/27 21:26
stimim:記憶體(硬體)是人設計的,他們也可以做一個記憶體,你存取 08/27 21:38
stimim:某些特定的值就會出事,os 或是 程式要自己想辦法避開 08/27 21:39
stimim:現在的記憶體幾乎都是連續整數只是方便而已,未來會怎麼樣 08/27 21:40
stimim:誰也不知道 08/27 21:40