考虑这段代码:
const char* someFun() {
// ... some stuff
return "Some text!!"
}
int main()
{
{ // Block: A
const char* retStr = someFun();
// use retStr
}
}
在函数
someFun()
中,"Some text!!"
存储在哪里(我认为它可能在ROM的某个静态区域中)以及它的retStr
指向的内存会在整个程序中被占用还是一旦A块退出就被释放?
C++ 标准没有规定字符串文字应该存储在哪里。然而,它确实保证它们的生命周期就是程序的生命周期。因此您的代码是有效的。
"Some text!!"
没有范围。 Scope 是named 实体的属性。更准确地说,它是名称本身的属性。 "Some text!!"
是一个 nameless 对象 - 字符串文字。它没有名称,因此任何关于其“范围”的讨论都没有任何意义。它没有范围。
您似乎要问的不是范围。它是"Some text!!"
的生命周期或
存储持续时间。 C/C++ 中的字符串文字具有静态存储持续时间,这意味着它们“永远”存在,即只要程序运行。所以,
"Some text!!"
占用的内存永远不会被释放。
请记住(作为旁注)字符串文字是不可修改的对象。写入该内存是非法的。
字符串将静态存储在程序二进制文件的特殊部分(在现代操作系统上通常是只读的)。它的内存未分配(单独为字符串,仅在将其加载到内存时为总部分分配)并且不会被释放。
我发布了类似问题的答案,所以我也将在这里使用该示例:
简短的答案是字符串文字
message2
将存在于内存中
只要进程执行,但在 .rodata 部分(假设我们正在讨论 ELF 文件)。
我们返回一个指向字符串常量的指针,但正如我们稍后将看到的,没有在任何地方定义单独的内存来存储这个
const char *
指针,
没有必要,因为字符串的地址是在代码中计算的,并在每次调用函数时使用寄存器$rax
返回。
但是让我们看一下代码中 GNU 调试器 (GDB) 发生了什么:
我们在返回指向常量字符串的指针的函数中放置了一个断点,我们看到了汇编代码和流程图:
代码通过以下指令获取该字符串:
0x000055555555514a <+8>: lea 0xeb3(%rip),%rax # 0x555555556004
这条指令的作用是计算
message2
的地址。
我们在这里了解位置无关代码 (PIC) 的含义。
message2
字符串的地址不是硬编码为绝对地址,而是计算为相对地址,作为下一条指令地址(0x555555555151 + 0xeb3)的硬编码偏移0xeb3并放入寄存器rax
中。
相对寻址(当前地址+/-偏移量)的目的意味着进程将始终获得正确的地址
message2
,无论它加载到内存中的哪个位置。
所以在这里我们看到您要求的
const char *
实际上并不存在于内存中,因为地址是“动态”计算并使用$rax
返回的:
我们的地址在
$rax
:
(gdb) i r $rax
rax 0x555555556004 93824992239620
它保存着
message2
的地址:
(gdb) x/s 0x555555556004
0x555555556004: "message2"
现在让我们看看地址
0x555555556004
在进程地址映射中的位置:
0x555555556000 0x555555557000 0x1000 0x2000 r--p /home/drazen/proba/main
因此该部分不可执行且不可写,只是可读且私有(r--p),这是有道理的,因为这不是共享库。
当我们使用
readelf
检查时,它显示它位于 ELF 文件的 .rodata 部分中:
drazen@HP-ProBook-640G1:~/proba$ readelf -x .rodata main
Hex dump of section '.rodata':
0x00002000 01000200 6d657373 61676532 00 ....message2.
所以答案是,这个字符串不会被硬编码在 ELF 文件的代码段.text、只读数据段.rodata中,但是只要进程存在于内存中,它就会存在。
添加一个小细节,这个常量字符串将通过引用返回到 main() 函数,当然是(地址),但不是在堆栈上;而是在寄存器中
rax
:
(gdb) i r
rax 0x555555556004 93824992239620
rbx 0x0
retStr指向的内存会在整个程序中被占用还是一旦A块退出就被释放?
它将不发布,但
retStr
将不可用。 (块范围)
const char *ptr;
{
const char* retStr = "Scope";
ptr = retStr;
}
printf("%s\n", ptr); //prints "Scope"
//printf("%s\n", retStr); //will throw error "retStr undeclared"