[英]Why do (only) some compilers use the same address for identical string literals?
我可以在MSVC生成的匯編代碼中看到兩個'some'
文字,但只有一個有clang和gcc。 這導致完全不同的代碼執行結果。
static const char *A = "some";
static const char *B = "some";
void f() {
if (A == B) {
throw "Hello, string merging!";
}
}
任何人都可以解釋這些編譯輸出之間的差異和相似之處嗎? 為什么即使沒有請求優化,clang / gcc也會優化某些內容? 這是某種未定義的行為嗎?
我還注意到,如果我將聲明更改為下面顯示的聲明,則clang / gcc / msvc根本不會在匯編代碼中留下任何"some"
。 為什么行為不同?
static const char A[] = "some";
static const char B[] = "some";
這不是未定義的行為,而是未指定的行為。 對於字符串文字 ,
允許編譯器(但不是必需的)將存儲組合為相等或重疊的字符串文字。 這意味着當通過指針進行比較時,相同的字符串文字可能會也可能不會比較相等。
這意味着A == B
的結果可能是true
或false
,你不應該依賴它。
從標准, [lex.string] / 16 :
是否所有字符串文字都是不同的(即,存儲在非重疊對象中)以及是否對字符串文字的連續評估產生相同或不同的對象是未指定的。
其他答案解釋了為什么你不能指望指針地址不同。 然而,您可以輕松地以保證A
和B
不比較相等的方式重寫它:
static const char A[] = "same";
static const char B[] = "same";// but different
void f() {
if (A == B) {
throw "Hello, string merging!";
}
}
不同之處在於A
和B
現在是字符數組。 這意味着它們不是指針,它們的地址必須是不同的,就像兩個整數變量必須的那樣。 C ++混淆了這一點,因為它使指針和數組看起來可以互換( operator*
和operator[]
似乎表現相同),但它們確實不同。 例如const char *A = "foo"; A++;
const char *A = "foo"; A++;
是完全合法的,但const char A[] = "bar"; A++;
const char A[] = "bar"; A++;
不是。
考慮差異的一種方法是char A[] = "..."
說“給我一塊內存並用字符填充...
后跟\\0
”,而char *A= "..."
說”給我一個地址,我可以在那里找到字符...
然后是\\0
“。
編譯器是否選擇對A
和B
使用相同的字符串位置取決於實現。 在形式上,您可以說您的代碼行為未指定 。
兩種選擇都正確地實現了C ++標准。
這是節省空間的優化,通常稱為“字符串池”。 以下是MSVC的文檔:
https://msdn.microsoft.com/en-us/library/s0s0asdt.aspx
因此,如果將/ GF添加到命令行,您應該會看到與MSVC相同的行為。
順便說一句,你可能不應該通過這樣的指針比較字符串,任何體面的靜態分析工具都會將該代碼標記為有缺陷。 您需要比較它們指向的內容,而不是實際的指針值。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.