在C和C++中,字符串字面量的类型是什么?

74

C中的字符串字面值的类型是什么?是char *还是const char *或者是const char * const?

C++呢?

4个回答

71
在C语言中,字符串字面值的类型是char[],根据类型它不是const的,但修改其内容是未定义行为。此外,两个具有相同内容(或足够相同内容)的不同字符串字面值可能共享或可能不共享相同的数组元素。
来自C99标准6.4.5/5 "字符串字面值-语义":
“在第7个翻译阶段,一个值为零的字节或代码将被附加到由字符串字面值或多个字符串字面值导致的每个多字节字符序列之后。然后使用多字节字符序列初始化具有静态存储期和长度的数组,只能包含该序列。对于字符字符串字面值,数组元素的类型为char,并使用多字节字符序列的单个字节进行初始化。对于宽字符串字面值,数组元素的类型为wchar_t,并用广泛字符序列进行初始化...”
“这些数组是否不同不确定,只要它们的元素具有适当的值。如果程序尝试修改这样的数组,则行为是未定义的。”
在C++中,“普通字符串字面量的类型为'n const char'的数组”(来自2.13.4/1“字符串字面值”)。但在C++标准中有一种特殊情况,即使是指向字符串字面值的指针也可以轻易地转换为非const限定的指针(4.2/2“数组到指针的转换”):
“不是宽字符串字面量的字符串字面量(2.13.4)可以转换为类型为'char指针'的rvalue; 宽字符串字面量可以转换为类型为'wchar_t指针'的rvalue。”作为一条附加说明 - 因为C/C++中的数组很容易转换为指针,因此字符串字面值通常可以在指针上下文中使用,就像C/C++中的任何数组一样。
补充说明:接下来我对C和C++标准在字符串字面值类型选择方面所做的选择的原理进行了大量猜测。 因此,带着怀疑的态度来看待它(但如果您有更正或其他细节,请发表评论):
我认为,C标准选择使字符串字面值成为非const类型,是因为有很多代码期望能够使用指向文字的非const限定符char指针。当添加const限定符时(如果我没有弄错的话,这是在ANSI标准化时期完成的,但在K&R C存在并积累了大量现有代码之后),如果将指向字符串字面值的指针只能被分配给char const *类型而不需要转换,则几乎每个现有程序都需要更改。这不是一个让标准得到批准的好方法......
我认为,将字符串字面值更改为const限定符的C++变化主要是为了支持允许文字字符串更适当地匹配需要“char const*”参数的重载。 我认为还有一种关闭类型系统中感知的漏洞的愿望,但是这个漏洞很大程度上在数组到指针转换的特殊情况下被打开了。
标准的附录D指出,“从const到非const限定符的字符串字面值(4.2)的隐式转换已被弃用”,但我认为有太多的代码仍会崩溃,以至于编译器实现者或标准委员会将不愿意真正断开插头(除非可以设计出其他巧妙的技术 - 但是然后漏洞又回来了,不是吗?)。

11

C语言中的字符串字面量类型是char [n],其中 n 等于字符数+1,以考虑到字符串末尾的隐式零。

该数组将被静态分配;它不是const的,但修改它是未定义的行为。

如果它具有指针类型char *或不完整类型char [],则sizeof不能按预期工作。

将字符串字面量设置为const是C++的习惯用法,而不是任何C标准的一部分。


2
由于历史上的一些原因,在C语言中,字符串字面量一直是char[]类型。早期(在C90中),规定修改字符串字面量会引发未定义行为。然而,他们并没有禁止这种修改,也没有将字符串字面量设为const char[],尽管这样做更有意义。这是为了向后兼容旧代码。一些旧操作系统(最著名的是DOS)不会对修改字符串字面量提出异议,因此有很多这样的代码存在。
即使在最新的C标准中,C语言仍然存在这个缺陷。
C++从C中继承了同样的缺陷,但在后来的C++标准中,它们最终将字符串字面量标记为const(在C++03中被标记为过时,在C++11中最终修复)。

1

它们以前是char[]类型。现在它们是const char[]类型。


+1 指针..指向哪里?在哪里?哦,你说编译器会为我完成这个魔法。 - Tim Post
5
请注意,这次更改引入了从const char[]到char[]的标准转换。这是为了避免破坏所有已经定义了类似于“int foo(char*)”函数的现有代码。 - Glen
1
@JayConrod char x[]="abc"; 是一种特殊情况,它声明了一个类型为 char[4] 的变量,并按指定方式进行初始化。这是 char x[4] = {0x61,0x62,0x63,0}; 的简写形式,因此该字符串字面值不像其他字符串字面值那样被编译器放置在某个未命名位置。特别地,它不会像大多数字符串字面值那样被放置在某个未命名位置。 - greggo
3
以前是什么时候?什么时候发生了变化? - Ciro Santilli OurBigBook.com
2
你没有说明你指的是C语言,但我假设是这样。C99和2011年的标准似乎与你所说的相矛盾:C99 6.4.5,§6说“如果程序试图修改这样的数组,则行为未定义”;C2011的§7也是如此。当然,理智的编译器(或那些关心你的理智的编译器)会在需要时为您标记此问题。 - PJTraill
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接