除了全局和静态数据之外,还有哪些在数据段上分配了什么?
我记得在某处读取了在数据段上也分配了常量字符串,并且在对相同的字符串常量进行引用时使用了相同的内存
例如:
char* returnPointer()
{
char *p = "hello world"
//some code
return p;
}
void foo()
{
char *s = "hello world"
//some code
}
在上面的代码中,
是否在数据分段或堆栈上分配了常量“hello world”的内存(就像任何其他本地变量一样)?
如果在数据段上分配,p和s是否指向同一位置?
答案 0 :(得分:2)
在数据分段或堆栈上分配常量“hello world”的内存(就像任何其他本地变量一样)吗?
不,它在一些只读实现定义的内存区域中被分配。 C标准没有准确定义应该存储的位置。它仅保证字符串文字具有 静态存储持续时间 ,并且不应由用户程序修改。
如果在数据段中分配,
p
和s
是否指向同一位置?
这完全取决于所使用的编译器的效率。高效的编译器可能只优化和分配单个字符串,而另一个编译器可能不会这样做。
无论如何,您应该依赖这些行为,因为它们与语言的用户无关,它们是用户程序不应该依赖的实现细节。
答案 1 :(得分: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
中放置了一个副本。
答案 2 :(得分:0)
关于第一个问题,答案是“hello world”将存储在只读存储区中。
对于你的第二个问题,答案是它可能会也可能不会。不能保证它们具有相同的地址。
以下更多信息:
初始化数据段:
初始化数据段,通常简称为数据段。数据段是程序虚拟地址空间的一部分,它包含由程序员初始化的全局变量和静态变量。
请注意,数据段不是只读的,因为变量的值可以在运行时更改。
该段可以进一步分为初始化只读区域和初始化读写区域。
例如,C中的char s [] =“hello world”定义的全局字符串和主要(即全局)之外的int debug = 1之类的C语句将存储在初始化的读写区域中。像const char * string =“hello world”这样的全局C语句使字符串文字“hello world”存储在初始化的只读区域中,字符指针变量字符串存储在初始化的读写区域中。
Ex:static int i = 10将存储在数据段中,global int i = 10也将存储在数据段中
未初始化的数据段:
未初始化的数据段,通常称为“bss”段,以古代汇编运算符命名,代表“由符号启动的块”。此段中的数据在程序开始执行之前由内核初始化为算术0
未初始化的数据从数据段的末尾开始,包含初始化为零或在源代码中没有显式初始化的所有全局变量和静态变量。
例如,变量声明为static int i;将包含在BSS部分中。 例如,一个声明为int j的全局变量;将包含在BSS部分中。