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

Pra*_*ari 0 c c++ compiler-construction string

在Turbo C/C++的日子里,您可以轻松修改字符串

char * str = "Hello";
str[1] = '1'; //it will make it H1llo;
Run Code Online (Sandbox Code Playgroud)

现在存储它们.bss,您不能直接修改它们.为什么?这不会使修改字符串变得困难吗?

对它有任何快速解决方法(但没有副作用)吗?我strdup()喜欢功能,但直接修改字符串真的很有趣.

Ton*_*roy 10

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

原因是编译器可能会在代码中的许多位置看到一个文字,例如:

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

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

in z.cpp:    q = "StackOverflowError";
Run Code Online (Sandbox Code Playgroud)

非常希望避免让所有这些字符串文字分别出现在可执行映像和加载的进程内存中; 相反,编译器可以安排包含"StackOverFlowError\0"的单个存储区域,并在使用点使用指向相关起始字符(无论是'S'还是'E')的指针.

如果您被允许修改该值 - 可能决定您希望x.cpp显示"Alert"而不是"Error",则可能会无意中破坏y.cpp和z.cpp中的代码.

有快速解决方案吗?

好吧,如果取决于你的想法是什么打破了.如果你的意思是修改字符串文字的方法,那么没有......由于上面解释的原因,这是未定义的行为,并且内存保护机制会因操作系统等而异.如果你的意思是能够修改文本数据类似的方式,然后是:char* s = "abc";放在s堆栈上,但它指向你观察到的.bss数据.如果你改为写:

char s[] = "abc";
Run Code Online (Sandbox Code Playgroud)

然后s仍然在堆栈上,但现在是一个空格为4个字符的数组,字符串文字仍然在.bss中,但每当该行运行时,它从后者复制到前者,之后你就可以修改基于堆栈的复制ala s[1] = 'x';.

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