Leo*_*eon 12 c++ constants lifetime null-terminated constexpr
我有如下功能:
const char* get_message() {
return "This is a constant message, will NOT change forever!";
};
const char* get_message2() {
return "message2";
};
Run Code Online (Sandbox Code Playgroud)
我计划在我的应用程序的任何地方使用它们,即使在不同的线程中。
const char*
我想知道这些字符串的生命周期,即在函数之外使用这些字符串是否安全get_message
。
我猜想硬编码const char*
字符串将被编译到应用程序的代码段而不是数据段中,所以也许像上面那样使用它们是安全的?
Jam*_*nze 16
从标准给出答案,"message"
是一个字符串文字,并且字符串文字具有静态生命周期,这意味着该对象(char const[N]
包含字符的对象)具有整个程序的生命周期。(对于具有重要构造函数或析构函数的对象来说,情况要复杂一些)。因此指向它的指针在程序的生命周期内都有效。
是的,这样做是安全的。你的假设是正确的。
\n\n\n
const char*
我想知道这些字符串的生命周期,即在函数之外使用这些字符串是否安全get_message
。
那么快速浏览一下标准。
\n\n\n评估字符串文字会产生具有静态存储持续时间的字符串文字对象,该对象从上面指定的给定字符初始化。未指定所有字符串文字是否不同(即存储在不重叠的对象中)以及字符串文字的连续计算是否产生相同或不同的对象。[注意:尝试修改字符串文字的效果未定义。\xe2\x80\x94结束注]
\n
\n\xe2\x80\x94-ISO/IEC JTC1 SC22 WG21 N4860(第 5.13.5 节 [字符串文字])
所以是的。在函数计算字符串文字并将 a 返回const char*
到字符串文字后,标准确保该字符串文字将被赋予静态存储持续时间。
简短的答案是字符串文字“message2”将与进程一样存在于内存中,但在. 罗达塔部分(假设我们谈论 ELF 文件)。
我们返回指向字符串常量的指针,但正如我们稍后将看到的,没有在任何地方定义单独的内存来存储该指针,并且没有必要,因为字符串的地址是在代码中计算的,并在每次函数调用时const char *
使用寄存器 $ rax返回叫。
但是让我们看看代码中gdb发生了什么
我们在函数中放置断点,返回指向常量字符串的指针,我们看到汇编代码和流程图:
代码通过以下指令获取该字符串:
0x000055555555514a <+8>: lea 0xeb3(%rip),%rax # 0x555555556004
Run Code Online (Sandbox Code Playgroud)
该指令的作用是计算“message2”的地址。我们在这里看到 PIC(位置无关代码)的含义。
“message2”字符串的地址不是硬编码为绝对地址,而是计算为相对地址,作为下一条指令地址 (0x555555555151 + 0xeb3) 的硬编码偏移 0xeb3 并放入寄存器rax中。
相对寻址(当前地址+/-偏移量)的目的意味着进程将始终获得“message2”的正确地址,无论它加载到内存中的何处。
所以在这里我们看到const char *
你问的实际上并不存在于内存中,因为地址是“动态”计算并使用 $rax 返回的:
我们在 $rax 中有地址:
(gdb) i r $rax
rax 0x555555556004 93824992239620
Run Code Online (Sandbox Code Playgroud)
它保存“message2”的地址:
(gdb) x/s 0x555555556004
0x555555556004: "message2"
Run Code Online (Sandbox Code Playgroud)
现在让我们看看进程地址映射中的地址0x555555556004在哪里:
0x555555556000 0x555555557000 0x1000 0x2000 r--p /home/drazen/proba/main
Run Code Online (Sandbox Code Playgroud)
因此,该部分不可执行且不可写,只是可读且私有(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.
Run Code Online (Sandbox Code Playgroud)
所以答案是,这个字符串不会被硬编码在 ELF 文件的代码段.text中,而是只读数据段.rodata,但是,当内存中存在长进程时,它会存在。
只是为了添加一些小细节,这个常量字符串当然会通过引用(地址)返回到 main() 函数,但不是在堆栈上,而是在寄存器rax中:
(gdb) i r
rax 0x555555556004 93824992239620
rbx 0x0
Run Code Online (Sandbox Code Playgroud)
希望能帮助到你!
归档时间: |
|
查看次数: |
1058 次 |
最近记录: |