2017-09-06 64 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

相关问题