2013-05-31 39 views
5

我有一個簡單的程序:這兩個指針爲什麼相等?尋求澄清。

int main() { 
    char *c = "message"; 
    char *z = "message"; 

    if (c == z) 
     printf("Equal!\n"); 
    else 
     printf("Not equal!\n"); 
    return 0; 
} 

我想知道爲什麼這個打印Equal!,即使在編譯的優化關閉(-O0)。這表明cz指向相同的存儲器區域,因此z(例如,將z[0]更改爲a)的第一個突變將是昂貴的(需要複製和寫入)。

我發生了什麼事的理解是,我不聲明char類型的數組,而是正在創建一個指向​​的第一個字符。因此,cz都存儲在數據段中,而不是在堆棧上(並且因爲它們都指向相同的字符串文字,所以c == z爲真)。

這是爲了寫入不同:

char c[] = "message"; 
char z[] = "message"; 

if (c == z) printf("Equal\n"); 
else printf("Not equal!\n"); 

它打印Not equal!,因爲cz都存儲在存儲器可變部分(即,疊層),並單獨存儲,使得一個突變一個不會影響另一個。

我的問題是,是我看到的行爲(如c == ztrue)定義的行爲?令人驚訝的是char *c存儲在數據段中,儘管沒有被聲明爲const

行爲當我試圖改變char *z定義?爲什麼,如果char *c = "message"被放入數據段並且因此是隻讀的,那麼我得到bus error而不是編譯器錯誤?例如,如果我這樣做:

char *c = "message"; 
c[0] = 'a'; 

我得到:

zsh: bus error ./a.out 

雖然它編譯愉快。

任何進一步的澄清,以及爲什麼會感激。

+4

你**不能**突變這些;這是未定義的行爲。 –

+0

[char \ *和const char * *之間的區別]的可能的重複(http://stackoverflow.com/questions/9834067/difference-between-char-and-const-char) –

+0

@OliCharlesworth對於那個接受的答案問題指出:「'char * name'你可以改變名稱指向的字符,也可以改變它指向的字符」,即'name'不是隻讀的。你在說,試圖寫入'name'將會是不確定的,這是不一致的(即我錯過了某些東西)。有什麼不同? – simont

回答

2

C 2011標準。第6.4.5節。字符串文字。第7段

它是未指定的這些陣列是否[字符串文字]是不同的條件是它們的元素具有適當的值。如果程序試圖修改這樣一個數組,那麼行爲是不確定的。

這意味着,如果兩個字符串文字具有相同的值,編譯器允許有他們指向同一個內存位置,或不同的,但它只是一個選擇的編譯器可以做到的。

7

「的z第一突變(例如,改變z[0]a)將是昂貴的(需要複製和寫入)。」

不「昂貴」;嘗試undefined。字符串文字是常量。

1

C編譯器的一個步驟是在代碼中找到一組所有字符串常量。它將只存儲任何不可變字符串的一個副本,即使該字符串在代碼中存在兩次。因此,在你的例子中,你有兩次"message"--編譯器將在文件中(在只讀數據部分)存儲m e s s a g e \0,然後初始化這兩個指針指向字符串。

嘗試使字符串不同,指針現在應該不同了。

而且,試試這個:打印您的可執行文件(如果它的通話a.out,運行cat -v a.out)。你會看到字符串「消息」,「相等!」和「不相等!」坐在可執行文件中。

更新:(刪除,因爲它是錯誤的。)下面是生成的代碼:

8048449:  c7 44 24 1c 6d 65 73 73 movl $0x7373656d,0x1c(%esp) 
8048451:  c7 44 24 20 61 67 65 00 movl $0x656761,0x20(%esp) 
8048459:  c7 44 24 24 6d 65 73 73 movl $0x7373656d,0x24(%esp) 
8048461:  c7 44 24 28 61 67 65 00 movl $0x656761,0x28(%esp) 
8048469:  b8 70 85 04 08   mov $0x8048570,%eax 

它兩次創造這個十六進制字符串(我的機器是小端):

6d 65 73 73 61 67 65 00 
m e s s a g e \0 

所以你是對的 - 它把字符串放在可變內存中。

+0

您的更新是錯誤的。修改數組'c []'和'z []'完全可以。它們不再連接到用於初始化它們的字符串文字。在數組的情況下,字符串文字內容被複制。 OP所引用的陳述是正確的。 –

+0

這是真的。我更新了更新。 –

+0

編譯器不需要使字符串的兩個副本不同,但它可以。 –

0

文字「消息」是一個常量,存儲在只讀存儲器中,編譯器只保留一個副本。我不知道最新的標準,但是從編譯器到編譯器的使用都不一樣。