【问题标题】:Where is the string stored with functions that return a hard-coded string literal?与返回硬编码字符串文字的函数一起存储的字符串在哪里?
【发布时间】:2017-12-05 00:40:45
【问题描述】:

我在 C/C++ 代码中看到过这个:

char * GetName()
{
  return "Aurian";
}

引擎盖下到底发生了什么? "Aurian" 存储在内存中的哪个位置,以便在我离开 GetName() 范围时它仍然存在,并且我得到一个 char * ?我猜它不遵循与返回 int 相同的规则。以及这有什么关系

char * name = "Aurian";

这个实现是否依赖?另外,GetName() 会被编译成 "Aurian" 吗?

This thread 似乎暗示某种跳转表可用于所有字符串文字,无论如何用于 GCC。

【问题讨论】:

  • 你应该得到a warning关于const char* -> char*转换的信息。
  • 在实践中,字符串文字(通常)位于为文字保留的只读内存段中,因此该函数返回指向该段中字符串的指针。其他太大而不能作为直接操作数的文字——例如双精度浮点常量——将在同一段中。您对优化器可能会做什么的描述有点模糊。如果函数是自动内联的,则返回指向字面量的指针的函数调用将被简单地使用指针本身替换。
  • 与其他所有字符串字面量相同的位置(即静态存储区)
  • 是的,你的字符串在内存中的位置取决于实现。
  • C 和 C++ 的答案不同。建议只用其中一种语言标记这篇文章。

标签: c++ c string pointers memory


【解决方案1】:

看起来字符串常量存储在数据段的只读部分(以及其他非零初始化静态变量)。检查组装!

我编译这个

#include<stdio.h>
  char * GetName()
  {
     return "Aurian";
  }
  int main()
  {
      printf("%s", GetName());
      return 0;
  }

组装看起来像

    .section    .rodata
    .LC0:
      .string "Aurian"
      .text
      .globl  GetName
      .type   GetName, @function
  GetName:
  .LFB0:
      .cfi_startproc
      pushq   %rbp
      .cfi_def_cfa_offset 16
      .cfi_offset 6, -16
      movq    %rsp, %rbp
      .cfi_def_cfa_register 6
      movl    $.LC0, %eax
      popq    %rbp
      .cfi_def_cfa 7, 8
      ret
      .cfi_endproc
  .LFE0:
      .size   GetName, .-GetName
      .section    .rodata
  .LC1:
      .string "%s"
      .text
      .globl  main
      .type   main, @function
  main:
  .LFB1:
      .cfi_startproc
      pushq   %rbp
      .cfi_def_cfa_offset 16
      .cfi_offset 6, -16
      movq    %rsp, %rbp
      .cfi_def_cfa_register 6
      movl    $0, %eax
      call    GetName
      movq    %rax, %rsi
      movl    $.LC1, %edi
      movl    $0, %eax
      call    printf
      movl    $0, %eax
      popq    %rbp
      .cfi_def_cfa 7, 8
      ret
      .cfi_endproc

【讨论】:

  • 好的,所以我真的不知道汇编,但看起来在只读数据段(.rodata)中有一个地址(.LC0),其中字符串“Aurian”是存储。然后,在 GetName 函数中,看起来我们将 LC0 复制到 eax,我猜它是一个存储 GetName 的返回值的寄存器。基本上是这样吗?
  • 所有这些 .Lxx: 都是标签。检查这篇帖子stackoverflow.com/questions/5325326/… .LC 局部常量 .LFB 函数开始,.LFE 函数结束,是的,字符串常量的地址被放入累加器(eax)寄存器,然后作为 printf 调用的参数发送。这是程序布局的图片en.wikipedia.org/wiki/File:Program_memory_layout.pdf
【解决方案2】:

它用作函数的退出代码,因此它的存储位置取决于操作系统。 C 语言不指定这些低级细节。它们因平台而异。

在 UNIX 风格的系统中,该值将是 wait()waitpid() 系统调用的返回值。 在调用这些函数之前,返回码会存储在 linux 内核的 PID 条目中。

众所周知

  • 全局变量,静态变量,动态变量有Heap 存储

  • 函数的指针和参数都有Stack存储

  • 常量变量存储在代码本身(数据段)

因此基于这些类型,这些变量存储在堆栈中,直到它们从堆栈帧中返回

在您的情况下,函数在堆栈调用堆栈帧以隐式返回后在堆栈上找到空间

当它们被返回时,它们被存储在 CPU 寄存器中。我们可能会消耗两个或更多的 CPU 寄存器,这取决于操作系统

【讨论】:

  • 虽然我认为您所说的任何内容都没有错,但您似乎误解了这个问题。这只是函数返回指向字符的指针后字符的存储位置。与进程或线程的返回值无关。
猜你喜欢
  • 1970-01-01
  • 2012-07-12
  • 2015-10-25
  • 2017-10-03
  • 2013-11-09
  • 1970-01-01
  • 1970-01-01
  • 2010-12-24
  • 1970-01-01
相关资源
最近更新 更多