为什么字符串文字是常量?

时间:2013-01-28 20:50:58

标签: c++ string const literals

众所周知,在C ++中,字符串文字是不可变的,修改字符串文字的结果是未定义的。例如

char * str = "Hello!";
str[1] = 'a';

这将导致未定义的行为。

此外,字符串文字放在静态内存中。因此它们存在于整个程序中。我想知道为什么字符串文字有这样的属性。

5 个答案:

答案 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中固定字符串文字。)