0

除了全局和静态数据之外,数据段上还分配了什么?

我记得在某处读到常量字符串也分配在数据段上,并且当引用相同的字符串常量时使用相同的内存

前任:

char* returnPointer()
{
   char *p = "hello world"

   //some code

   return p;
}

void foo()
{
   char *s = "hello world"
  //some code
}

在上面的代码中,

  1. 是否在数据段或堆栈上分配了常量“hello world”的内存(就像任何其他局部变量一样)?

  2. 如果在数据段上分配,p 和 s 是否都指向同一个位置?

4

3 回答 3

2

是否在数据段或堆栈上分配了常量“hello world”的内存(就像任何其他局部变量一样)?

不,它被分配在一些只读实现定义的内存区域中。C 标准并没有准确定义它应该存储在哪里。它仅保证字符串文字将具有静态存储持续时间,并且不应由用户程序修改。

如果在数据段上分配,两者是否都p指向s同一个位置?

这完全取决于所使用的编译器的效率。一个高效的编译器可能只优化和分配一个字符串,而另一个编译器可能不会这样做。

无论如何,您应该依赖这些行为,因为它们与语言的用户无关,它们是用户程序不应该依赖的实现细节。

于 2012-05-31T05:59:20.487 回答
2

是否在数据段或堆栈上分配了常量“hello world”的内存(就像任何其他局部变量一样)?

这是特定于编译器的,但通常字符串文字存在于初始化数据段上(通常是初始化数据段的特殊只读部分)。我不知道字符串文字可以合理地存在于堆栈上的任何架构。

如果在数据段上分配,p 和 s 是否都指向同一个位置?

这取决于编译器。

当我使用 gcc 4.4.6 编译您的代码时,我看到以下内容:

        .section        .rodata
.LC0:
        .string "hello world"
        .text
.globl returnPointer
        .type   returnPointer, @function
returnPointer:
.LFB0:
        .cfi_startproc
        ...
        movq    $.LC0, -8(%rbp)
        ...
        ret
        .cfi_endproc
.LFE0:
        .size   returnPointer, .-returnPointer
.globl foo
        .type   foo, @function
foo:
.LFB1:
        .cfi_startproc
        ...
        movq    $.LC0, -8(%rbp)
        ...
        ret
        .cfi_endproc
.LFE1:
        .size   foo, .-foo
        .ident  "GCC: (GNU) 4.4.6 20110731 (Red Hat 4.4.6-3)"

在这里,字符串文字存储在只读数据 ( .rodata) 部分中。编译器足够聪明,可以意识到完全相同的文字在编译单元中被使用了两次,并且它只将它的一个副本放入.rodata.

于 2012-05-31T05:59:55.770 回答
0

对于您的第一个问题,答案是,“hello world”将存储在只读内存区域中。

对于您的第二个问题,答案是它可能会或可能不会。不能保证它们具有相同的地址。

下面还有一些信息:

初始化数据段:

初始化数据段,通常简称为Data Segment。数据段是程序虚拟地址空间的一部分,其中包含由程序员初始化的全局变量和静态变量。

请注意,数据段不是只读的,因为变量的值可以在运行时更改。

该段可以进一步分为初始化只读区和初始化读写区。

例如,由 C 中的 char s[] = “hello world” 定义的全局字符串和 main 之外的诸如 int debug=1 的 C 语句(即全局)将存储在初始化的读写区域中。而像 const char* string = “hello world” 这样的全局 C 语句使字符串文字“hello world”存储在初始化的只读区域中,而字符指针变量 string 则存储在初始化的读写区域中。

例如:静态 int i = 10 将存储在数据段中,全局 int i = 10 也将存储在数据段中

未初始化的数据段:

未初始化的数据段,通常称为“bss”段,以一个古老的汇编运算符命名,代表“由符号开始的块”。该段中的数据在程序开始执行前被内核初始化为算术0

未初始化的数据从数据段的末尾开始,包含所有初始化为零或在源代码中没有显式初始化的全局变量和静态变量。

例如一个变量声明为 static int i; 将包含在 BSS 段中。例如一个全局变量声明为 int j; 将包含在 BSS 段中。

于 2012-05-31T05:59:44.050 回答