Re: [心得] 用 extern 誤導編譯器,及用VC看組譯碼

看板C_and_CPP (C/C++)作者 (躂躂..)時間16年前 (2009/06/19 17:54), 編輯推噓4(4011)
留言15則, 4人參與, 最新討論串2/2 (看更多)
※ 引述《zlw (www.eJob.gov.tw)》之銘言: 我倒覺得這覺這會錯..其實是因為.... 這樣本來就寫錯了吧 orz 先考慮下這樣的定義 int a[2]={100,200}; int *p; 然後 p = a; 0x1000 ├─── │ a[0]=100 0x1004 ├─── │ a[1]=200 0x1008 ├─── │ p=0x1000 ├─── a本身代表 array a[] 所在的址, 所以 a[1] == *(a+1) == *(0x1000 + 1*sizeof(int)) == *(0x1004) 而因為 p=a; 所以 p[1] == *(p+1) == *(0x1000 + 1*sizeof(int)) == *(0x1004) 到這邊為止, 應該都是你也知道的東西 .___." 可是仔細看看你會發現.. 其實 p 本身是有塊 storage 去放他的, 也就是 p=0x1000 這個 value 是被存在 0x1008 這個位址.. 但 "a=0x1000" 這個 0x1000 本不會被存在哪裡呀.. 並不像 p 會被存下來一樣.. (這根function/method本身的address,也不會有塊storage去存他們是一樣的意思) 再回頭看來最一開始的問題就很清楚了, int a[2] = {100,200}; 和 extern int *a; int a[2] 表示有 define 兩塊 storage 去放 a[0] 和 a[1] 但 *a 卻是說, define 了一個 storage 去放一個pointer 在第一個 .c 裡會說, symbole a 的 address 在 0x1000 0x1000 ├─── 在第二個 .c 檔寫成 extern int *a; │a[0]=100 會變成說 a 這個用來放pointer的storage在 0x1000 0x1004 ├─── 而不是 a的內容是 0x1000 │a[1]=200 換個講法, 一個意思是 0x1008 ├─── a = 0x1000;, 這樣你才能 a[i] .. │ 另一個的意思 0x100C ├─── &a = 0x1000, │ 所以 a 的內容當然會變成 100 囉 > 利用 extern 可以對全域變數「重新宣告」資料型態一次。但怪就怪在 > 不能把全域變數 double a = 0; 重新宣告成 extern int a; (中略) > warning C4743: 'int * arr' 在 1.cpp 及 src.cpp 中有不同的大小: 8 和 4 位元組 > warning C4744: 'int * arr' 在 1.cpp 及 src.cpp' 中有不同的型別: 'array (8 > bytes)' 和 'pointer' 這個應該是 VC9 太聰明了, 還多去檢查這個 @.@a 一般來說, 應該是每個 .c(source) 自己是獨立編譯的, 編出來的 objects 檔再 link 起來.. link 恐怕只會看到symbole對應的address而不會看到size 用 gcc 在 command line 編就不會看到這種訊息了 @.@ -- 類似的惡搞法還有... 搾出 class method 的 address, 然後把他當 c function 呼叫...||| -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 140.112.41.173 ※ 編輯: cole945 來自: 140.112.41.173 (06/19 17:55) ※ 編輯: cole945 來自: 140.112.41.173 (06/19 17:55) ※ 編輯: cole945 來自: 140.112.41.173 (06/19 17:56)

06/19 18:09, , 1F
謝謝。看到資料說,像這樣錯誤extern在規格中是「未定義行為」
06/19 18:09, 1F

06/19 18:09, , 2F
所以沒有被阻擋這樣寫。可是如果1.cpp定義double a;則他在
06/19 18:09, 2F

06/19 18:10, , 3F
symbol table會被裝飾名稱成?a@@3NA,而src.cpp裡extern int a
06/19 18:10, 3F

06/19 18:11, , 4F
會被裝飾名稱成?a@@3HA,所以這種情況會連結錯誤。也只有在
06/19 18:11, 4F

06/19 18:11, , 5F
陣列名稱跟指標時,才會名稱一致,然後就被騙的跑出錯誤指令
06/19 18:11, 5F

06/19 18:21, , 6F
推~ 可以請教一下 &p為什麼會是在0x1008呢 stack不是丟在上
06/19 18:21, 6F

06/19 18:21, , 7F
面嘛 0x1000-4之類的
06/19 18:21, 7F

06/19 18:30, , 8F
只是舉例方便吧...不用太在意。push新資料後,ESP會變小沒錯
06/19 18:30, 8F

06/19 18:31, , 9F
只是舉例方便吧??
06/19 18:31, 9F

06/19 22:17, , 10F
zlw說的對@_@ 我沒注意到是在討論C++. C++的話, 因為type
06/19 22:17, 10F

06/19 22:18, , 11F
的問題, 直接link就錯誤了 @o@
06/19 22:18, 11F

06/19 22:19, , 12F
其實要嚴格講的話~ 也不是所有平台stack長的方向都一樣@.@
06/19 22:19, 12F

06/19 22:19, , 13F
往哪個方向長其實不用那麼在意囧"
06/19 22:19, 13F

06/19 22:27, , 14F
剛研究了一下g++編出來的東西,好像只有function在mangling
06/19 22:27, 14F

06/19 22:28, , 15F
所以不同type卻相同name的變數,也有可能發生link錯誤 @.@
06/19 22:28, 15F
文章代碼(AID): #1AEs1mEn (C_and_CPP)
文章代碼(AID): #1AEs1mEn (C_and_CPP)