Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/150.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/58.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么字符串在新编译器中不可修改_C++_C_String_Compiler Construction - Fatal编程技术网

C++ 为什么字符串在新编译器中不可修改

C++ 为什么字符串在新编译器中不可修改,c++,c,string,compiler-construction,C++,C,String,Compiler Construction,在Turbo C/C++时代,您可以轻松地修改字符串,如 char * str = "Hello"; str[1] = '1'; //it will make it H1llo; 现在它们存储在.bss中,不允许您直接修改它们。为什么?这难道不会使修改字符串变得困难吗 有没有什么速效药(但没有副作用)?我可以strdup()像函数一样,但是直接修改字符串真的很有趣。在C标准下修改字符串文本是未定义的行为 您可以使用较旧的编译器执行此操作,但这并不意味着它在所有编译器中都是合法的,它们只是过去更

在Turbo C/C++时代,您可以轻松地修改字符串,如

char * str = "Hello";
str[1] = '1'; //it will make it H1llo;
现在它们存储在
.bss
中,不允许您直接修改它们。为什么?这难道不会使修改字符串变得困难吗


有没有什么速效药(但没有副作用)?我可以
strdup()
像函数一样,但是直接修改字符串真的很有趣。

在C标准下修改字符串文本是未定义的行为

您可以使用较旧的编译器执行此操作,但这并不意味着它在所有编译器中都是合法的,它们只是过去更为宽松,不保护您写入此内存区域

你可以做:

char str[] = "Hello";
str[1] = '1';

这将创建一个可变的
字符数组
,并使用字符串文本值的副本(包括
\0
终止符)对其进行初始化。

正如您所观察到的,标准不允许您修改字符串文本内容,现代编译器/OSs会相应地安排内存权限

原因是编译器可能会在代码的许多地方看到使用的文本,例如:

in x.cpp:    std::cerr << "Error" << separator << msg << '\n';

in y.cpp:    if (x == "Error") ...

in z.cpp:    q = "StackOverflowError";
然后,
s
仍然在堆栈上,但现在是一个有4个字符空间的数组,字符串文本仍然在.bss中,但每当该行运行时,它都会从后者复制到前者,之后您可以修改基于堆栈的副本ala
s[1]=“x”

当然,将数据放入std::string通常是更好的方法。

回答“为什么”问题。其他人已经提到的一个微不足道的回答是“这是未定义的行为”。这意味着标准允许编译器做任何编译器想做的事情


但为什么它是未定义的行为?原因是,在大型软件项目中,常常会出现数千个重复字符串,如果宏检测到某些不一致并打印出消息,可能会导致程序崩溃。此宏在数千个位置重复,每次都打印相同的消息。如果字符串是可修改的,则消息必须在最终二进制文件中复制数千次。为了防止大量链接器对二进制文件中的字符串执行重复数据消除,这意味着如果您有
printf(“foo\n”);printf(“foo\n”)
在程序中,两个
“foo\n”
字符串将位于同一内存位置。现在假设您有:
char*foo=“foo\n”;printf(“foo\n”)
编译器可能认为它可以消除字符串的重复数据,而在程序中的其他地方,您可以这样做
*foo='b'。现在printf将不正确。为了防止这种情况发生,修改字符串文字是一种未定义的行为,现代编译器将利用这一事实来消除字符串的重复(比我这里的示例要高级得多),并希望以这样一种方式生成程序:修改字符串文字将崩溃。

在Visual Studio Atlet中不会崩溃。@ss7don如果这是真的,有足够的理由不在这里使用特定版本的VS.@ss7don,“Hello”是
str
的初始值设定项
str
不是常量或字符串文字,因此它是可写的。同意您的回答,但与编译器的行为相混淆。“标准不允许您修改字符串文字内容”——这是不正确的;该标准并不禁止修改字符串文字,它只是没有指定如果您这样做会发生什么——这意味着这样做的程序不是符合要求的程序,但该标准不要求程序符合要求,而且大多数程序也不要求。有些实现确实允许修改字符串文字(其中一个由市场领导者提供),而我所咨询的一家公司的旗舰程序在过去17年左右的时间里包含了此类代码。@JimBalter:忽略“不允许”与“不允许”业务。。。它是未定义的,这不仅仅是标准的“无法指定如果您这样做会发生什么”,而是说实现也不需要指定它——尽管它们肯定会这样做。你在说哪个编译器?VisualC++表示它未定义。我99.999%确定它不是为GCC定义的实现。很难想象其他编译器会被认为是市场领导者,但我洗耳恭听……这不仅仅是——是的,是的。这意味着实现也不需要指定它——实现也不需要向您发送一百万美元。。。标准没有要求他们这样做,这一点也不有趣。所有的标准都是定义一个一致的实现或程序所需的。VisualC++——嗯,“在某些情况下,可以将相同的字符串文字组合起来”。“以节省可执行文件中的空间。在字符串文字池中,编译器会使对特定字符串文字的所有引用指向内存中的同一位置,而不是使每个引用指向字符串文字的单独实例/GF启用了字符串池。“我洗耳恭听……”——你的眼睛好像有问题。@Mihai:涡轮也曾生活在过去。可怜的我们。
char s[] = "abc";