string文字:他们去哪里?
我感兴趣的是在哪里string文字分配/存储。
我在这里find了一个有趣的答案,他说:
定义一个内联string实际上是embedded在程序本身的数据,不能改变(一些编译器允许这个聪明的把戏,不要打扰)。
但是,这与C ++有关,更不用说它不说了。
我很烦。 = d
所以我的问题是我的string文字保存在哪里以及如何? 为什么我不应该试图改变它? 实施是否因平台而异? 有没有人关心“巧妙的把戏”?
一个常见的技术是将string文字放在“只读数据”部分,该部分被映射到进程空间中为只读(这就是为什么您不能更改它)。
它确实因平台而异。 例如,更简单的芯片架构可能不支持只读存储器段,因此数据段将是可写的。
相反,然后尝试找出一个技巧,使string文字可变(这将高度依赖于您的平台,并可能随时间而改变),只是使用数组:
char foo[] = "..."; 编译器将安排数组从文字初始化,您可以修改数组。
没有人回答这个问题。 C和C ++标准只是说,string文字具有静态存储持续时间,任何修改它们的尝试都会给出未定义的行为,并且具有相同内容的多个string文字可能共享或不共享相同的存储。
根据您要编写的系统以及它使用的可执行文件格式的function,可能会将它们与程序代码一起存储在文本段中,也可能有一个用于初始化数据的独立段。
确定细节也会根据平台而变化 – 最有可能包括可以告诉你它放在哪里的工具。 有些甚至会让你控制这样的细节,如果你想要的话(例如gnu ld允许你提供一个脚本来告诉它如何分组数据,代码等)
为什么我不应该试图改变它?
因为它是未定义的行为。 来自C99的报价N1256草稿6.7.8 / 32“初始化” :
例8:声明
char s[] = "abc", t[3] = "abc";定义“简单的”字符数组对象
s和t其元素用string文字初始化。这个声明是一样的
char s[] = { 'a', 'b', 'c', '\0' }, t[] = { 'a', 'b', 'c' };数组的内容是可修改的。 另一方面,声明
char *p = "abc";定义
p的types为“指向char的指针”并将其初始化为指向长度为4的types为“char的数组”的对象,其元素用string文字初始化。 如果尝试使用p来修改数组的内容,则行为是不确定的。
他们去哪里?
GCC 4.8 x86-64 ELF Ubuntu 14.04:
-   char s[]:堆栈
-   char *s:-   .rodata节的对象文件
-  对象文件的.text部分被转储的同一个段,具有Read和Exec权限,但不包含Write
 
-   
程序:
 #include <stdio.h> int main() { char *s = "abc"; printf("%s\n", s); return 0; } 
编译和反编译:
 gcc -ggdb -std=c99 -c main.c objdump -Sr main.o 
输出包含:
  char *s = "abc"; 8: 48 c7 45 f8 00 00 00 movq $0x0,-0x8(%rbp) f: 00 c: R_X86_64_32S .rodata 
 所以string存储在.rodata节中。 
然后:
 readelf -l a.out 
包含(简体):
 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2] LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000 0x0000000000000704 0x0000000000000704 RE 200000 Section to Segment mapping: Segment Sections... 02 .text .rodata 
 这意味着默认链接脚本将.text和.rodata转储到可以执行但不能修改的段( Flags = RE )。 尝试修改这样的段会导致Linux中发生段错误。 
 如果我们对char[]做同样的处理: 
  char s[] = "abc"; 
我们获得:
 17: c7 45 f0 61 62 63 00 movl $0x636261,-0x10(%rbp) 
 所以它被存储在堆栈中(相对于%rbp ),我们当然可以修改它。 
仅供参考,只是备份其他答案:
标准: ISO / IEC 14882:2003说:
2.13。 string文字
[…]一个普通的string文字的types为“
n const char数组”和静态存储时间(3.7)
是否所有string文字都是不同的(即,是否存储在非重叠对象中)是由实现定义的。 尝试修改string文字的效果是未定义的。
  gcc使得一个.rodata节被映射到地址空间的某个地方并被标记为只读, 
  Visual C ++( cl.exe )为同一目的制作.rdata节。 
 您可以查看dumpbin或objdump (在Linux上)的输出以查看可执行文件的各个部分。 
例如
 >dumpbin vec1.exe Microsoft (R) COFF/PE Dumper Version 8.00.50727.762 Copyright (C) Microsoft Corporation. All rights reserved. Dump of file vec1.exe File Type: EXECUTABLE IMAGE Summary 4000 .data 5000 .rdata <-- here are strings and other read-only stuff. 14000 .text 
这取决于您的可执行文件的格式 。 一种考虑的方法是,如果你是汇编编程,你可能会把string文字放在汇编程序的数据段中。 你的C编译器做类似的事情,但这一切都取决于你正在编译的二进制文件系统。
string文字经常分配给只读存储器,使它们不可变。 然而,在一些编译器修改是可能的一个“聪明的把戏”。聪明的把戏是“使用字符指针指向内存”..记住一些编译器,可能不允许这..这里是演示
 char *tabHeader = "Sound"; *tabHeader = 'L'; printf("%s\n",tabHeader); // Displays "Lound" 
由于编译器和编译器可能有所不同,最好的方法是为search到的string文本过滤对象转储:
 objdump -s main.o | grep -B 1 str 
 其中-s强制objdump显示所有段的全部内容, main.o是对象文件, main.o强制grep在匹配之前也打印一行(这样就可以看到段名), str是string你正在寻找的文字。 
 在Windows机器上使用gcc,并在main声明一个variables 
 char *c = "whatever"; 
赛跑
 objdump -s main.o | grep -B 1 whatever 
回报
 Contents of section .rdata: 0000 77686174 65766572 00000000 whatever....