C& C ++ String Literal对char * =“stringLiteral”的弃用;

时间:2012-11-07 17:40:47

标签: c++ c

我了解语法 char * =“stringLiteral”; 已被弃用,将来可能无法使用。我不明白的是为什么

我搜索了网络和堆栈,虽然有许多回声确认char * =“stringLiteral”;错了, const char * =“stringLiteral”;是核心,我还没有找到有关WHY表示语法错误的信息。换句话说,我想知道问题究竟是什么。

错误我的混乱

CODE SEGMENT 1 - EVIL WAY(已弃用)

char* szA = "stringLiteralA";     //Works fine as expected. Auto null terminated.
std::cout << szA << std::endl;    
szA = "stringLiteralB";          //Works, so change by something same length OK.
std::cout << szA << std::endl;    
szA = "stringLiteralC_blahblah"; //Works, so change by something longer OK also.
std::cout << szA << std::endl;    

Ouput:
stringLiteralA
stringLiteralB
stringLiteralC_blahblah

那究竟是什么问题呢?似乎工作得很好。

CODE SEGMENT 2(“OK”方式)

const char* szA = "stringLiteralA";  //Works fine as expected. Auto null term.
std::cout << szA << std::endl;    
szA = "stringLiteralB";          //Works, so change by something same length OK.
std::cout << szA << std::endl;    
szA = "stringLiteralC_blahblah"; //Works, so change by something longer OK also.
std::cout << szA << std::endl;    

Ouput:
stringLiteralA
stringLiteralB
stringLiteralC_blahblah

也工作正常。没有不同。添加const有什么意义?

CODE SEGMENT 3

const char* const szA = "stringLiteralA";  //Works. Auto null term.
std::cout << szA << std::endl;    
szA = "stringLiteralB";           //Breaks here. Can't reasign.

我只是在这里说明为了只读保护变量内容你必须使用const char * const szA =“something”;

我没有看到弃用或任何问题。为什么不推荐使用此语法并将其视为问题?

4 个答案:

答案 0 :(得分:6)

const char *是常量(*const的指针(char)(指针定义可以从右到左轻松读取)。这里的重点是保护内容,因为正如标准所说,修改这种指针的内容会导致不确定的行为。

这源于这样一个事实:通常(C / C ++)编译器将整个程序中使用的字符串分组到单个内存区域中,并且允许对不相关部分中使用的相同字符串的实例使用相同的内存位置该程序(最小化可执行文件大小/内存占用)。如果允许修改字符串文字,则可能会影响另一个更改其他相同文字的无关实例,这显然不是一个好主意。

事实上,对于大多数现代编译器(在支持内存保护的硬件上),字符串表的内存区域是只读的,因此如果您尝试修改字符串文字,程序将崩溃。将const添加到引用字符串文字的指针会使这些错误立即显现为编译错误而不是崩溃。

顺便提一下,请注意字符串文字可以隐式地衰减到非const char *的事实只是向前兼容预标准库的一种让步(在const wasn时写的'如上所述,标准总是说改变字符串文字是UB。

答案 1 :(得分:2)

"abc"是一个静态数组,指向可能不可变的内存。 In C,修改字符串文字的内容是未定义的行为(UB)。


但是C99没有使"abc"成为const char [n]类型的对象。事实上,这是完全相反的,以保持与C89(和ANSI C)的兼容性,C89指定(§3.1.4/ 3):

  

字符串文字具有静态存储持续时间和类型 char 数组,并使用给定的字符进行初始化。

即宣言

char* c = "12345";

在C 中未被弃用,甚至高达C11。

http://www.open-std.org/jtc1/sc22/wg14/www/C99RationaleV5.10.pdf开始,我们可以看到C99中制作字符串文字修改UB的基本原理,同时保持类型为char [n]

  

字符串文字不需要是可修改的。此规范允许实现共享具有相同文本的字符串副本,将字符串文字放在只读存储器中,并执行某些优化。但是,字符串文字没有类型 const char 的数组,以避免指针类型检查的问题,特别是对于库函数,因为将指针分配给const char 到一个简单的指向char 的指针是无效的。那些坚持字符串文字应该可以修改的C89委员会成员满足于将这种做法指定为共同的延伸(见§J.5.5)

其中C99§J.5.5是:

  

J.5.5可写字符串文字

     

字符串文字是可修改的(在这种情况下,相同的字符串文字应表示不同的对象)(6.4.5)。


另一方面,由于您的代码是C ++,在标准C ++中实际上应该 错误 ,因为它需要(C ++03§2.13.4/ 1)

  

...普通字符串文字的类型为“ n const char数组”和静态存储持续时间......

并将const char[n]分配给char*不应该编译。编译器警告“弃用”,因为当时的现有实现允许转换(因为C允许),因此它进入附件D:兼容性功能:

  

D.4来自const字符串的隐式转换

     

不推荐使用字符串文字(4.2)从const到非const限定的隐式转换。

答案 2 :(得分:2)

弃用背后的想法是帮助编译器捕获可能导致运行时崩溃的错误。

char *hello = "hello";
strcpy(hello, "world"); // Compiles but crashes

而不是

const char *hello = "hello";
strcpy(hello, "world"); // Does not compile

这是捕获整个非常讨厌的运行时错误的一种相对便宜的方式,因此转换的弃用非常符合C ++作为“更好的C”的一般原则。

此外,您的代码段2不会使指针内容受到保护这一事实无效。指针本身被写入,而不是其内容。 const char *ptrchar * const ptr之间存在差异:前者保护内容;后者保护指针本身。这两者可以结合起来保护指针及其内容为const char * const ptr

答案 3 :(得分:0)

语法错误,因为没有从 char const * 隐式转换为 char *

在C和C ++中,字符串文字的类型一直是 char const * 。 (对于很老的C,可能是错的。)

规则的更改与字符串文字的类型无关,但允许在指针类型之间进行转换。

转换是一个错误,因为指向const的东西是不可变的东西。字符串文字是一个已知在编译和链接时保持不变的值,可以放在只读内存段中。