C++字符串字面值数据类型的存储

19
void f()
{
    char *c = "Hello World!"
}

这个字符串存储在哪里?它有什么属性?我只知道它是一个常量,还有什么其他的吗?我能从函数体内返回它吗?

8个回答

22

它已经和你的二进制文件捆绑在一起了——所谓的捆绑是指硬编码,因此你可以返回它并在其他地方使用它。但是你无法更改它,我强烈建议你将其声明为:

const char * x = "hello world";

1
我怀疑如果不加上const限定符,它甚至都无法编译。 - Billy ONeal
我模糊地记得老式的C编译器配置文件会拒绝编译没有“const”的代码。 - Hassan Syed
@Rahul G:今天我学到了一些东西 :)(在评论中点赞)不过那真的很愚蠢... - Billy ONeal
@BillyONeal:就像我在下面提到的那样,由于据我所知C++规范并没有规定这些必须是只读的,所以没有理由将其作为const在语言层面进行强制。 - David Pfeffer
@Rahul,现在是可以的。但是C++0x将禁止对char*进行赋值。它已经从const字面数组到char*的弃用转换中删除了此功能。 - Johannes Schaub - litb
@BillyONeal 它确实可以编译,但是将字符串常量转换为char 已经被弃用。请参见此在线gcc编译器[链接](https://gcc.godbolt.org/#compilers:!((compiler:g447,options:'+-O0',source:'%23include%3Ciostream%3E%0A%23include%3Cstring%3E%0Ausing+namespace+std%3B%0Astring+display()%7B%0A++char+cstring%3D+%22hell%22%3B%0A++int+a+%3D+sizeof+cstring%3B%0A++string+str%3D%22hel%22%3B%0A++return+%22string%22%3B%0A%7D%0A%0Aint+main()%7B%0A++char+cstring%5B%5D%3D%22hellohello%22%3B%0A++return+0%3B%0A%7D')),filterAsm:(binary:!t,colouriseAsm:!t,commentOnly:!t,directives:!t,labels:!t),version:3)。 - Gab是好人

7
该字符串存储在程序的数据区域中。这完全取决于编译器、可执行格式和平台。例如,ELF二进制文件将其放置在与Windows可执行文件不同的位置,如果您正在编译嵌入式平台,则此数据可能存储在ROM而不是RAM中。
下面是ELF格式的布局示意图: ELF Layout 您的字符串数据很可能位于.data或.text部分,具体取决于编译器。
您可以从函数体内返回它。只需检查您的实现以验证它是否是随机访问的,因为许多实现不允许您覆盖它。

可执行格式并未定义字符串字面量的存储方式。 - Billy ONeal
当然可以。几个可执行标准规定了在文件中放置静态数据的位置。 - David Pfeffer
1
虽然你在第一段中说的有一定道理,但我不会对事情采取如此强硬的立场——“检查实现以查看是否可以更改const”是给某人非常糟糕的建议。你暗示可能有一个C实现可以这样做——其实并没有,任何这样做的方式都是一种HACK。(尽管我不会-1)。 - Hassan Syed
@David:是的,ELF 有 .text 和 .data 段 -- 但两个部分都没有关于存储常量字符串数据的说明。编译器可以自由选择这样做,但它不是格式标准化的一部分。 - Billy ONeal
@HassanSyed 对于更改常量的错误建议的评论点赞 +1。 - beluchin
显示剩余2条评论

6

§2.14.15 字符串字面值,第7节

狭义字符串字面值的类型为“长度为n的const char数组”,其中n是下文中定义的字符串大小,并具有静态存储期


5

通常情况下,它被存储在只读内存区域,并具有静态存储分配。

执行像c [0] ='k'等操作会引发未定义行为。

我可以从函数体内返回它吗?

可以的!


3

它具有静态存储期,因此在程序的整个生命周期内存在。编译器/链接器放置初始化数据的确切位置会有所不同。从函数返回指向它的指针是可以的,但请确保返回一个char const * -- 对字符串进行写操作会导致未定义的行为。


1

这是实现定义的。大多数情况下,它将与程序中的所有其他字符串存储在一个字符串表中。通常,您可以将其视为全局静态const变量,但它无法在函数外部访问。


0

字符串字面量存储在数据段并在编译时分配。这有助于将相同的字符串字面量分配给多个变量,而无需创建字符串的副本。

例如,char * str="hello";

str是char指针,具有字符'h'的地址,而"hello"存储在数据段中,不能更改。尝试更改它会生成分段错误。

在分配字符数组字符串字面量时,在堆栈上创建字符串的副本。

即 char str[]="hello";

"hello"被复制到堆栈(以空字符结尾),并且str指向堆栈中的字符'h'。


-3

我已经有一段时间没有使用C++了,但我记得我(自学)在字符串(好吧,字符数组...)方面遇到了很多问题。

如果你要修改它们的值,请确保使用new和delete关键字... 大致如此...

char *strText = new char[10];
/* Do something
...
...
...
*/
delete [] strText;

马丁


你必须将 new[]delete[] 匹配,而不是 delete。或者只需使用 std::string - fredoverflow
那是我的错 - 我记不得要这样做了... 再说,C++对我来说已经很久远了 - Borland Turbo C++适用于MSDOS... - Martin Milan
有些编译器在不加方括号的情况下正确处理 delete,但我不会依赖它。 - Ton van den Heuvel
如果每个人都立即根据 SO 上的评论修正他们的答案,问题在于评论将仍然存在,并会对那时正确答案的可信度产生怀疑。在我看来,最好只是承认你错了(见上文)并继续前进... - Martin Milan
或者如果人们修正了答案,它就不会是错误的,然后他们可以添加一条评论说:“嘿,感谢指出错误,已经被更正…” - gnarf
Gnarf - 我已经指出我的原始答案是错误的 - 但你说得对。因此,现在阅读它的任何人,答案已经相应地进行了修改... - Martin Milan

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