※ 引述《Aligu1009 (=.=)》之銘言:
: 請問各位
: char *str="test";
: 這種寫法
: 這個字串會被當作是const而不能更改
: 類似的寫法如:
: char str[] = "test";
: 這個字串就是可變更的了
: C為什麼要對第一種寫法做這種限制呢? 謝謝
因為要提供兩種 implement 的方法?前者會被放到 read-only section,後者
會被放到 stack。
這是 char.c:
#include <stdio.h>
int main(void)
{
char *a1 = "test123456";
char a2[] = "test654321";
}
這是 gcc -O0 -S char.c 所產生出來的 char.s:
gslin@netnews [~/work/C] [17:41/W3] cat char.s
.file "char.c"
.section .rodata
.LC0:
.string "test123456"
.LC1:
.string "test654321"
.text
.p2align 2,,3
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
pushl %edi
pushl %esi
subl $32, %esp
andl $-16, %esp
movl $0, %eax ; 這五行是什麼鬼... 該不會 -O0
addl $15, %eax ; 就是這麼廢吧 XD
addl $15, %eax
shrl $4, %eax
sall $4, %eax
subl %eax, %esp ; 空出一塊 stack space
movl $.LC0, -12(%ebp)
leal -40(%ebp), %edi ; %edi = destination
movl $.LC1, %esi ; %esi = source
cld ; copy order
movl $11, %ecx ; copy 11 bytes
rep ; 這兩個指令就是 copy 的動作
movsb
leal -8(%ebp), %esp
popl %esi
popl %edi
leave
ret
.size main, .-main
.ident "GCC: (GNU) 3.4.4 [FreeBSD] 20050518"
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 140.113.54.119
> -------------------------------------------------------------------------- <
作者: cppOrz (cppOrz) 看板: C_and_CPP
標題: Re: [問題] char *str="test"是const字串的問題
時間: Fri Nov 18 02:31:27 2005
※ 引述《firose (guest)》之銘言:
: ※ 引述《Aligu1009 (=.=)》之銘言:
: : 謝謝你的回覆 :)
: : 可是我還是不懂
: : C幹麼要這樣子做呢?
: : 直接用個關鍵字const來限制
: : 閱讀上會更清楚啊?
: char *str="test"; //指標
: char str[] = "test"; //陣列
: 首先 "test" 是 const char[] 的一個常數值, 會被放到唯讀區域
這可能請對標準比較熟的人解釋一下,常數或字串常數,在 C/C++ 中
的實作是編譯器自行決定的。一般為了效率考量,通常是放在 const
data 區段;某些編譯器可能將它放在 overlapping objects 裏,做
為一種選擇性的優化機制。企圖修改它們,會導致未定義的後果;所
以雖然允許你拿個 char * 指著,但改了就爆。
會 ASM 的人當然可以研究一下自己手上的 C/C++ 編譯器究竟是怎麼
處理某些細節的。不過很多問題,真的是「先弄清楚定義」,自己有
個底,可以節省很多盲目摸索的時間。
: 至於 C 為什麼讓 char *str 可以指向 "test", 可能有某種原因, 但就是不能改值
: 不過第二行就不一樣, 會在 stack 分配空間給 str 陣列並把 "test" 的值拷貝過去
: 所以你改的話是改 str 這個陣列的記憶體, 不是 "test" 的記憶體位置
為什麼 C 讓 char * 可以指向字串常數?這是由於 C 著重效率多過
嚴謹。找一本比較新的 C/C++ 課本,通常會告訴你,正確的寫法是:
char const *s = "test";
如果希望能改動,就自己指定一塊記憶體(避免編譯器的優化實現,
把它放到 const data 區域),例如:
char s[] = "test"; // 放在 stack 區域(這其實是下面的簡寫)
或
char s[] = { 't', 'e', 's', 't', '\0' }; // 原本的寫法
或
static char s[] = "test"; // 放在 global/static 區域
至於可以通融 non-const char * 版本的寫法,那是因為已經有成萬
上億行的舊程式碼這樣做了,標準不得不向現實妥協;但當然三令五
申告訴大家舊的寫法是不好的(depreciated),請不要再用。
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 59.120.214.120
> -------------------------------------------------------------------------- <
作者: firose (guest) 站內: C_and_CPP
標題: Re: [問題] char *str="test"是const字串的問題
時間: Fri Nov 18 15:57:36 2005
※ 引述《Aligu1009 (=.=)》之銘言:
:
: ... 略
:
: 只是 str1指的東西,為什麼要放到唯讀區呢?
: 改以int*為例
: 我們通常會用
: int i=5;
: int *ptr = &i;
: 這時我們仍可更改 *ptr
: 因為 i 並非在唯讀區
: 但改成 char* 後
: 我會直觀的認為 (雖然這樣是錯的)
: char *ptr = "test";
: "test"應該也要被放在非唯讀區
我覺得您的問題可能是誤解了 char str[] = "test" 這句
它的作法是先在某一塊記憶體 memory_a 中存放這五個字元 't', 'e', 's', 't', '\0'
然後再從 stack 找一塊空間 memory_b, 然後把 memory_a 開始的那五個字元拷貝過去
由於 memory_b 的型態是 char [] 不是 const char[] 因此可以更改
至於 char *str = "test" 也是一樣, 先在 memory_a 存放 "test" 這個字串常數
然後在 stack 找一塊空間給 str, 大小就僅是一個指標大小, 然後令它指向 memory_a
但是嚴格來說 "test" 是 const char[] 指標要指向它的話型態應該要是 const char*
而今天 char *str 可以指向它有某種特別的原因, 就如 cppOrz 大大文章中所說的那些
您以下面這個例子來類比並不合適, 因為光是敘述結構就跟首篇的 char str[] 不同
int i = 5;
int *pi = &i;
如果以上面的結構來說的話, 類比的敘述是像下面這樣
char str[] = "test";
char *pstr = str;
當然可以想見, 可以透過 pstr 來修改 str. 就如同可以透過 pi 來修改 i.
常數值顧名思義本來就是不能修改,不管是放在哪裡 (前面文章說的 const data 區,或
overlapping objects 或者可能有其他地方) 至少編譯器得限制您的修改權,讓您無法去
修改 "test" 的值。當然今天編譯器允許您用 char * 指向它 (因為某些原因),就有可
能會使您寫出用 char * 指標來修改 "test" 值的程式碼,編譯會過,但是其行為是未定
義的。
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 59.104.235.75