2017-09-06 89 views
18

下面的程序由於未定義行爲引發系統性分段錯誤(試圖修改字符串文字):C編譯器爲什麼不提示與字符串不兼容的類型?

int main() { 
    char *s = "immutable"; 
    s[0] = 'a'; 
    return 0; 
} 

不過,似乎是絕對沒有辦法告訴GCC/Clang的發出哪怕是一丁點的警告有關它(-Wall -Wextra -pedantic -std=c11不做任何事)。

尤其對於初學者來說,這種情況對於通知有用。即使對於非初學者來說,在一些稍微不太明顯的情況下,它可能會有所幫助:

void f(char *s) { 
    s[0] = '0'; 
} 

int main() { 
    char *s = "immutable"; 
    f("literal"); // oops 
    f(s); // oops 
    return 0; 
} 

此外,這將有助於加強在C編程一些const - 文化。

爲什麼這種情況被故意忽略?標準是否積極地禁止在這種情況下發布診斷信息,或者主要是爲了向後兼容(現在試圖強制執行它們會產生太多警告)?

+0

它不是默認的,因爲遺憾的是還有一堆以非常量正確方式編寫的遺留代碼。有些甚至早於C中增加了'const'。 – StoryTeller

+1

默認情況下啓用這種警告會導致警報疲勞。如果編譯器對此提出警告會很高興,但是仍然有太多的舊代碼會在此代碼中跳動,而仍然是正確的代碼。 – Art

回答

16

TL; DR C編譯器不會警告,因爲它們不會在那裏「看到」一個問題。根據定義,C字符串文字是空終止的數組。它只是說,

[...] [...]如果程序試圖修改這樣一個數組,行爲是 未定義。

所以,在編譯過程中,它是不知道一個char陣列應該表現爲一個字符串文字編譯器。只有修改的嘗試是禁止

相關閱讀:對於任何有興趣,請參閱Why are C string literals read-only?

這麼說,我不是很確定這是否是一個好選擇,但gcc-Wwrite-strings選項。

引述​​3210,

-Wwrite-strings

當編譯C,給字符串常量的類型const char[length]以便複製一個的地址轉換成非const char *指針產生一個警告。這些警告幫助您在編譯時查找可以嘗試寫入字符串常量的代碼,但只有在聲明和原型中使用const時非常小心。否則,這只是一個滋擾。這就是爲什麼我們沒有要求-Wall要求這些警告。

所以,它產生使用借殼方式警告。

根據定義,C 字符串文字(即字符串文字)是char具有空終止符的數組。該標準沒有要求他們是const合格。

價:C11,章

在翻譯階段7,字節或零值代碼被附加到從字符串產生字面或文字每個多字節 字符序列。然後使用多字節字符 來初始化足以包含該序列的靜態存儲持續時間和長度的數組,即 。對於字符串文字,數組元素有 類型char,並且使用多字節字符 序列的單個字節進行初始化。 [....]

使用上述選項使所以使用字符串文字作爲分配到一個非const類型的指針的RHS的字符串文字const合格觸發警告。

這是參照C11,章§6.7.3

如果試圖通過與非const-左值的使用 修改與常量限定類型定義的對象進行限定類型,行爲是未定義的。 [...]

所以,這裏的編譯器生成的const限定類型的分配到非const -qualified類型的警告。

相關爲什麼使用-Wall -Wextra -pedantic -std=c11不會產生這個警告是,再次引述報價

[...]這些警告幫助你找到在編譯時的代碼,可以嘗試編寫成字符串常量,但只有在聲明和原型中使用const時非常小心。否則,這只是一個滋擾。這就是爲什麼我們沒有要求-Wall要求這些警告。

+0

*「否則,這只是一個令人討厭的東西。」*這聽起來像誰寫的手冊是試圖爲自己的代碼找藉口:P。 – user694733

+0

嗯......也許不是? const-to-non-const既不允許也不隱含,並且保證診斷。強迫const邊限定可能會破壞一些有效的代碼,你知道嗎? –

+1

是的,您不能在遺留代碼中使用此選項。但是任何新代碼都應該努力保持正確。我發現有趣的是,手動聽起來過於防守。 – user694733

14

有此選項:-Wwrite-strings。它的工作原理是將字符串文字的類型從char[N]更改爲const char[N]。此更改與標準C不兼容,並會導致有效代碼被拒絕,並且在極少數情況下會無效地接受無效代碼。它沒有默認啓用。

不幸的是,由於在C中定義了字符串文字的方式,因此爲這個提供良好的警告,而不用更改語言是非常困難的。

+0

*「,在極少數情況下無效的代碼將被默認接受。」*這將如何發生?如果'-Wwrite-strings'使錯誤檢查更嚴格,這應該是不可能的。 – user694733

+4

@ user694733將一個字符串文字的地址賦值給一個const char(*)[]變量的代碼將被默默接受(除非它自上次選中以來已被更改),但在標準C中,不存在從'char(*)[]'爲const char(*)[]',所以這需要一個診斷。 – hvd

+0

不知道爲什麼有人會把字符串的地址,但我想你是正確的。我仍然認爲,關於正常情況下的警告'char * a =「x」;',超出了可能的問題。 – user694733

相關問題