作者cole945 (躂躂..)
看板C_and_CPP
標題Re: [心得] 用 extern 誤導編譯器,及用VC看組譯碼
時間Fri Jun 19 17:54:55 2009
※ 引述《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)
推 zlw:謝謝。看到資料說,像這樣錯誤extern在規格中是「未定義行為」 06/19 18:09
→ zlw:所以沒有被阻擋這樣寫。可是如果1.cpp定義double a;則他在 06/19 18:09
→ zlw:symbol table會被裝飾名稱成?a@@3NA,而src.cpp裡extern int a 06/19 18:10
→ zlw:會被裝飾名稱成?a@@3HA,所以這種情況會連結錯誤。也只有在 06/19 18:11
→ zlw:陣列名稱跟指標時,才會名稱一致,然後就被騙的跑出錯誤指令 06/19 18:11
推 QQ29:推~ 可以請教一下 &p為什麼會是在0x1008呢 stack不是丟在上 06/19 18:21
→ QQ29:面嘛 0x1000-4之類的 06/19 18:21
推 zlw:只是舉例方便吧...不用太在意。push新資料後,ESP會變小沒錯 06/19 18:30
推 VictorTom:只是舉例方便吧?? 06/19 18:31
→ cole945:zlw說的對@_@ 我沒注意到是在討論C++. C++的話, 因為type 06/19 22:17
→ cole945:的問題, 直接link就錯誤了 @o@ 06/19 22:18
→ cole945:其實要嚴格講的話~ 也不是所有平台stack長的方向都一樣@.@ 06/19 22:19
→ cole945:往哪個方向長其實不用那麼在意囧" 06/19 22:19
→ cole945:剛研究了一下g++編出來的東西,好像只有function在mangling 06/19 22:27
→ cole945:所以不同type卻相同name的變數,也有可能發生link錯誤 @.@ 06/19 22:28