首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >字符串字面值:它们会去哪里?

字符串字面值:它们会去哪里?
EN

Stack Overflow用户
提问于 2010-04-07 12:11:10
回答 8查看 86.6K关注 0票数 175

我感兴趣的是字符串字面值的分配/存储位置。

我确实找到了一个耐人寻味的答案here,他说:

定义字符串内联的

实际上将数据嵌入到程序本身中,并且不能更改(一些编译器通过一个聪明的技巧实现了这一点,不必费心)。

但是,它与C++有关,更不用说它说不用麻烦了。

我很烦人。=D

所以我的问题是,我的字符串应该放在哪里,如何保存?为什么我不应该尝试改变它呢?实现方式会因平台而异吗?有没有人愿意详细解释一下这个“聪明的把戏”?

EN

回答 8

Stack Overflow用户

回答已采纳

发布于 2010-04-07 12:16:22

一种常见的技术是将字符串放在“只读数据”部分中,该部分以只读的形式映射到进程空间(这就是您不能更改它的原因)。

它确实因平台而异。例如,较简单的芯片架构可能不支持只读存储器段,因此数据段将是可写的。

而不是试图找出一个技巧,使字符串文字可变(它将高度依赖于您的平台,并可能随着时间的推移而变化),只需使用数组:

代码语言:javascript
复制
char foo[] = "...";

编译器将安排数组从文字初始化,您可以修改数组。

票数 135
EN

Stack Overflow用户

发布于 2015-06-05 17:07:23

为什么我不应该尝试更改它?

因为它是未定义的行为。引用自C99 N1256 draft 6.7.8/32 "Initialization"

示例8:声明

char s[] = "abc",t3 = "abc";

定义“纯”字符数组对象st,它们的元素是用字符串文字初始化的。

此声明与

t[] s[] ={ 'a','b','c','\0‘},char ={ 'a','b','c’};

数组的内容是可修改的。另一方面,声明

char *p = "abc";

定义类型为"pointer to char“的数组,并将其初始化为指向一个类型为"array char”、长度为4的对象,该对象的元素由字符串文字初始化。如果试图使用p修改数组的内容,则行为是未定义的。

他们会去哪里?

GCC 4.8 x86-64 ELF Ubuntu 14.04:

目标文件的

  • char s[]:stack
  • char *s
    • .rodata段转储目标文件的.text段的同一段,该段具有读取和执行权限,但没有Write

权限

程序:

代码语言:javascript
复制
#include <stdio.h>

int main() {
    char *s = "abc";
    printf("%s\n", s);
    return 0;
}

编译和反编译:

代码语言:javascript
复制
gcc -ggdb -std=c99 -c main.c
objdump -Sr main.o

输出包含:

代码语言:javascript
复制
 char *s = "abc";
8:  48 c7 45 f8 00 00 00    movq   $0x0,-0x8(%rbp)
f:  00 
        c: R_X86_64_32S .rodata

因此,字符串存储在.rodata部分中。

然后:

代码语言:javascript
复制
readelf -l a.out

包含(简化):

代码语言:javascript
复制
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  R E    200000

 Section to Segment mapping:
  Segment Sections...
   02     .text .rodata

这意味着默认的链接器脚本将.text.rodata都转储到可以执行但不能修改的段(Flags = R E)中。试图修改这样的段会导致Linux中的段错误。

如果我们对char[]执行同样的操作

代码语言:javascript
复制
 char s[] = "abc";

我们得到:

代码语言:javascript
复制
17:   c7 45 f0 61 62 63 00    movl   $0x636261,-0x10(%rbp)

所以它被存储在堆栈中(相对于%rbp),我们当然可以修改它。

票数 60
EN

Stack Overflow用户

发布于 2010-04-07 12:20:46

这个问题没有一个答案。C和C++标准只是说字符串文字具有静态存储持续时间,任何修改它们的尝试都会产生未定义的行为,并且具有相同内容的多个字符串文字可能共享相同的存储空间,也可能不共享相同的存储空间。

根据您正在为其编写的系统以及它所使用的可执行文件格式的功能,它们可能与程序代码一起存储在文本段中,或者它们可能有一个单独的段用于初始化数据。

根据平台的不同,确定细节也会有所不同--最有可能包括的工具可以告诉您它放在哪里。有些甚至可以让你控制这样的细节,如果你想要的话(例如gnu ld允许你提供一个脚本来告诉你如何对数据、代码等进行分组)。

票数 56
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2589949

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档