C语言字符串字面量只读特性、类型及相关疑问解答
C语言字符串字面量相关问题解答
首先附上参考的书籍原文:
还有一类只读对象,其类型却无法阻止它们被修改,这类对象就是字符串字面量。
核心结论:字符串字面量是只读的。
如果是当下才引入字符串字面量,其类型肯定是char const[],即const限定的字符数组。遗憾的是,const关键字在C语言中的引入时间远晚于字符串字面量,为了保持向后兼容性,字符串字面量的类型就保留了最初的设定。
问题1:字符串字面量是只读的,为什么实际操作中看起来可以被修改?只读属性的生效逻辑是什么?
你所谓的“看起来可以被修改”本质是未定义行为的表现,不属于合法的可预期操作。
C标准本身明确规定修改字符串字面量的行为是未定义的,实际能不能修改完全取决于编译器和操作系统的配置:
- 大部分现代编译器默认会把字符串字面量放到进程虚拟地址空间的
.rodata(只读数据)段,这个段的页表属性被操作系统标记为不可写,一旦尝试修改就会触发段错误(SIGSEGV)直接崩溃; - 少数老旧编译器、或者主动给编译器开启了允许修改字符串字面量的参数(比如gcc的
-fwritable-strings选项)时,字符串字面量会被放到可写的数据段,这时候修改操作看起来能跑通,但这完全是编译器给的“例外”,不符合标准要求,也不具备可移植性。
只读属性的生效逻辑分两层:一是C标准的语法层面约定了字符串字面量不可修改,二是编译器+操作系统层面通过内存页权限控制做了实际的防护,两层共同保障只读属性,只要是符合标准实现的环境,修改操作都会被拦截。
问题2:引文中提到的“无法阻止被修改的类型”具体是什么?为什么该类型没有提供修改保护?
这里指的是char [](非const限定的字符数组)类型。
没有保护的原因完全是历史遗留:C语言刚发明的时候还没有const关键字,字符串字面量从诞生起就被设定为char[]类型,程序员可以直接拿char*指针指向它。等到C89标准把const加进来的时候,业界已经有海量的老代码直接用char*接收字符串字面量了,如果强行把字符串字面量的类型改成const char[],所有老代码都会报类型不兼容的编译错误,为了保持向后兼容性,标准只能保留原来的类型设定,相当于把修改风险转移给了程序员自己把控。
问题3:如何理解“如果当下引入字符串字面量,会被定义为char const[]即const限定的字符数组”的表述?
这个表述本质是从类型安全的角度倒推的合理设计:
- 字符串字面量本身是静态存储期的只读对象,天生就不应该被修改,给它加上
const限定,就能在编译期就拦截所有修改操作,从类型层面就避免了未定义行为的出现; char const[]的类型也完全匹配它的实际属性:是一段连续的字符数组,内容不可变更。如果现在重新设计C语言的字符串字面量,完全没有理由再保留非const的类型,加const既符合语义,又能增强类型安全性,不会有任何历史包袱。
内容的提问来源于stack exchange,提问作者dexter
相关产品推荐
相关产品推荐

