這主題不算是 c runtime, 只是我自己想這樣分類。
程式設計師面試寶典 (已經絕版, 連這種書都會絕版, 真讓我驚訝, 這可算是電腦界的高普考書籍耶!): p 7-6 提到的考題:
char c[]="hello";
char *c="hello";
有什麼不同?
書上花了近兩頁的篇幅在解釋, 不過沒有告訴你為什麼?也許你和我一樣, 會想知道為什麼? 看看翻出來的組合語言就知道了。
gcc -S a.c 得到 a.s
9 movl $1819043176, -6(%ebp)
10 movw $111, -2(%ebp)
1819043176 = 0x6C6C6568
111 = 0x6f
"hello" = {0x68, 0x65, 0x6c, 0x6c, 0x6f}
所以第 9, 10 行就是把 hello 放到 %ebp 指的 stack 中。
gcc -S a-ro.c 得到 a-ro.s
2 .section .rodata
3 .LC0:
4 .string "hello""hello" 是放在 .rodata section, 這會佔用執行檔案的空間, 所以執行檔會大一些。不過編譯後的執行檔案大小一樣, obj 檔倒是有大小的差異。可能還有我沒搞懂的地方。
看來差異不大, 但題目是如果把 c return 回去的話會怎樣?
char c[]="hello";
char *c="hello";
return c;
c[] 放在 stack 裡, 在 return 時,
stack 會被清掉不應該這麼描述, 應該說: stack 的位址很多 code 會使用 (ex: call a function), function return 時, 若要存取這個 stack 位址的時候沒有其他 code 來蓋掉這個 stack 位址, 那就不會有問題, 但這是無法保證的。所以無法預期 c[] 的值還會是 "hello", *c 則是在 .rodata, 在執行環境記憶體已經保留出一個位置存放 "hello", 所以沒有問題。
若程式執行起來沒問題, 那是運氣好, 不過, 相信我, 你不會一直有這樣的運氣, 這種 bug 很難找。
至於 *c 存在 .rodata, 所以 *c 指到的 "hello" 是無法修改的, 無法使用 c[0]='z' 來修改。既然唯讀, 也難怪大部份都是看到 const char *c="hello"; 這樣的寫法, 因為我讀過的書說要這樣寫,直覺的寫法就應該是這樣, 現在我知道為什麼了。
這也很讓我驚訝, C 是這麼隱晦不清的語言, char *c 從語法來看, 完全看不出來有 const 的意思, 也難怪在 The C Programming Language 之後, 會有那麼多的書籍來討論 C 語言了。
20120312 補充:
完全是我自己搞錯了。
float f=0.1;
int i=1;
f=i;
這通常很容易看出會有問題, 因為 f, i type 是不同的。
char *c="hello" 也是:
"hello" 是 const char pointer
c 是 char pointer,
兩個 type 也是不同, 把他們用 = 在一起, 會發生什麼事情, 自然是寫 code 的人要負責。
在 gcc 的測試下,
char *c="hello";
c[0]='Q';
在執行的時候會得到 Segmentation fault, 因為改變唯讀記憶體的位址, 所以有這樣的行為, 在編譯期間, compiler 沒有抓到這樣的警告, 我有點納悶。當然, 若是用 const char *c="hello";
編譯器就會警告了。
static array vs static pointer
測試讀寫的情形。
str[2]='q';static array 不會放到 .rodata, 所以可以讀寫。
pointer 的版本似乎都會將 "hello" 放到 .rodata (不管有沒 static), 所以看來 pointer 的版本應該都只能讀 (執行結果會得到 Segmentation fault), 不能寫。
size 差異:
7145 2011-12-09 16:00 a-static-array
7143 2011-12-09 16:00 a-static-pointer
20120117 補充:
在 C 程式語言 (第二版) p C-3 看到 16. 字串常數不再可被更改 ..., 也許就是描述這個情形。
英文版本在 p 260 Strings are no longer modifiable, and so may be placed inread-only memory.
沒有留言:
張貼留言
使用 google 的 reCAPTCHA 驗證碼, 總算可以輕鬆留言了。
我實在受不了 spam 了, 又不想讓大家的眼睛花掉, 只好放棄匿名留言。這是沒辦法中的辦法了。留言的朋友需要有 google 帳號。