众所周知,在C ++中,字符串文字是不可变的,修改字符串文字的结果是未定义的。例如
char * str = "Hello!";
str[1] = 'a';
这将导致未定义的行为。
此外,字符串文字放在静态内存中。因此它们存在于整个程序中。我想知道为什么字符串文字有这样的属性。
答案 0 :(得分:18)
有几个不同的原因。
一种是允许将字符串文字存储在只读存储器中(正如其他人已经提到的那样)。
另一种方法是允许合并字符串文字。如果一个程序在几个不同的地方使用相同的字符串文字,那么允许(但不一定要求)编译器将它们合并是很好的,因此您可以获得指向同一内存的多个指针,而不是每个指针占用一个单独的内存块。当两个字符串文字不一定相同但具有相同的结尾时,这也适用:
char *foo = "long string";
char *bar = "string";
在这种情况下,bar
可能foo+5
(如果我计算正确的话)。
在上述任何一种情况下,如果您允许修改字符串文字,它可以修改碰巧具有相同内容的其他字符串文字。同时,老实说也没有太多的要点 - 要么有足够的字符串文字可以重叠,大多数人可能希望编译器运行得更慢只是为了保存(可能)几十个字节记忆的左右。
在编写第一个标准时,已经有编译器使用了所有这三种技术(可能还有其他几种)。由于没有办法描述你从修改字符串文字中获得的一种行为,并且没有人显然认为它是一种重要的支持能力,所以他们做了显而易见的事情:即使试图这样做也会导致未定义的行为。
答案 1 :(得分:12)
修改文字是未定义的行为,因为标准是这样说的。标准说这样允许编译器将文字放在只读内存中。它出于多种原因这样做。其中之一是允许编译器优化只存储在源中重复多次的文字实例。
答案 2 :(得分:2)
我相信你会问到文字被放入的原因 只读内存,而不是链接器执行此操作的技术细节 禁止此类等标准的法律细节。
当修改字符串文字 时,会导致细微的错误 即使没有字符串合并(我们有理由这样做) 如果我们决定允许修改,则不允许)。当你看到像
这样的代码char *str="Hello";
.../* some code, but str and str[...] are not modified */
printf("%s world\n", str);
这是一个自然的结论,你知道将会打印什么,
因为str
(及其内容)未在特定情况下进行修改
在初始化和使用之间放置。
但是,如果字符串文字是可写的,则不知道任何字符 更多:str [0]可能会在以后,在此代码或内部覆盖 深度嵌套的函数调用,以及当代码再次运行时,
char *str="Hello";
不再保证str
内容的任何内容。和我们一样
期望,这个初始化实现为移动已知的地址
在链接时间到str
的地方。它没有检查str
包含“Hello”,它不会分配它的新副本。然而,
我们了解此代码将str
重置为“Hello”。这很难
克服这种自然的理解,很难理解
不保证的代码。当你看到像这样的表达式时
x+14
,如果您不得不考虑可能被覆盖的话,该怎么办?
在其他代码中,它变成了42?字符串也存在同样的问题。
这就是禁止修改字符串文字的原因 标准(没有要求及早发现故障)和 实际目标平台(提供检测潜力的奖励 错误)。
我相信许多解释这件事的尝试都受到了影响 最糟糕的循环推理。标准禁止写作 文字,因为编译器可以合并字符串,或者可以放置它们 在只读内存中。它们被放置在只读内存中以便捕获 违反标准。并且合并文字是有效的 标准禁止......这是你要求的一种解释吗?
让我们看看其他 语言。 Common Lisp standard 修改文字未定义的行为,即使是 前面Lisps的历史与C的历史非常不同 实现。那是因为可写文字逻辑上 危险的。语言标准和内存布局仅反映了这一点 事实。
Python语言恰好有一个类似的地方 “写入文字”可能会发生:参数默认值,以及此 事实confuses people all the time。
您的问题被标记为C++
,我不确定其当前状态
关于隐式转换到非const char*
:如果它是a
转换,是否已弃用?我希望其他答案能提供一个
关于这一点的完全启示。我们谈论其他语言
在这里,让我提一下简单的C.这里,字符串文字是不是 const,
并且要问的同等问题是为什么我不能修改字符串
文字(而且有更多经验的人会问,为什么
字符串文字非const如果我不能修改它们?)。然而
尽管存在这种差异,上述推理完全适用于C.
答案 3 :(得分:1)
因为是K& R C所以没有“const”这样的东西。同样在ANSI C ++之前。因此,有很多代码都有char * str = "Hello!";
之类的内容。如果标准委员会将文本文字设为const,那么所有这些程序都将不再编译。所以他们做出妥协。文字文字是官方文字const char[]
,但它们默默隐式转换为char*
。
答案 4 :(得分:0)
在C ++中,字符串文字是const
,因为您不被允许
修改它们。在标准C中,它们可能是const
好吧,除了当const
引入C时,有
那么多代码就像char* p = "somethin";
那样
使它们成为const会破坏,它被认为是
不能接受的。 (C ++委员会选择了不同的解决方案
这个问题,允许使用不推荐的隐式转换
以上。)
在原始C中,字符串文字是不是 const,而且是 可变,并且保证没有两个字符串文字共享 任何记忆。很快就意识到这是一个严重的错误, 允许这样的事情:
void
mutate(char* p)
{
static char c = 'a';
*p = a ++;
}
在另一个模块中:
mutate( "hello" ); // Can't trust what is written, can you.
(Fortran的一些早期实现有类似的问题,
F(4)
可能会使用几乎任何整数值调用F
。
Fortran委员会修正了这个问题,就像C委员会一样
在C中固定字符串文字。)