GCC存储的string常量以及这些指针映射的位置在哪里?

当我编译并运行我的Linux x86_64机器上的C程序时,由GCC编译:

#include <stdio.h> int main(void) { char *p1 = "hello"; // Pointers to strings char *p2 = "hello"; // Pointers to strings if (p1 == p2) { // They are equal printf("equal %p %p\n", p1, p2); // equal 0x40064c 0x40064c // This is always the output on my machine } else { printf("NotEqual %p %p\n", p1, p2); } } 

我总是得到的输出为:

等于0x40064c 0x40064c

我知道string存储在一个常量表中,但与dynamic分配内存相比,地址太低。

与以下程序比较:

 #include <stdio.h> int main(void) { char p1[] = "hello"; // char arrar char p2[] = "hello"; // char array if (p1 == p2) { printf("equal %p %p\n", p1, p2); } else { // Never equal printf("NotEqual %p %p\n", p1, p2); // NotEqual 0x7fff4b25f720 0x7fff4b25f710 // Different pointers every time // Pointer values too large } } 

两个指针是不相等的,因为这是两个可以独立操作的数组。

我想知道GCC如何为这两个程序生成代码,以及它们在执行过程中如何映射到内存。 由于这将已经logging了很多次,任何文档的链接也欢迎。

在这两种情况下,编译器.rodata在程序的.rodata节中发出字符串"hello"的实际字节( rodata代表只读数据 )。

它们实际上是直接从可执行文件映射到内存中,有点类似于代码段。 这就是为什么它们与动态分配的相距甚远。

然后:

 char *p = "hello"; 

只需将p初始化为此(只读)数据的地址即可。 显然:

 char *q = "hello"; 

获取相同的地址。 这被称为字符串池 ,是编译器的一个可选的流行优化。

但是当你写:

 char p[] = "hello"; 

它可能会产生这样的东西:

 char p[6]; memcpy(p, "hello", 6); 

作为"hello"实际上是只读池字符串的地址。

memcpy的调用仅用于说明目的。 这可能是非常好的复制内联,而不是一个函数调用。

如果以后你做:

 char q[] = "hello"; 

它将定义另一个数组和另一个memcpy() 。 所以相同的数据,但不同的地址。

但是,这些数组变量将驻留在哪里? 那么,这取决于。

  • 如果他们是本地的,非静态的,变量:在堆栈中。
  • 如果它们是全局变量,那么它们将位于可执行文件的.data节中,并且将在那里保存正确的字符,因此在运行时不需要任何memcpy 。 这很好,因为memcpy必须在main之前执行。
  • 如果它们是本地静态变量:与全局变量完全相同。 他们在一起被称为variables of static duration或类似的东西。

关于文档链接,对不起,我不知道。

但是,如果您可以自己做实验,谁需要文档? 为此,最好的工具是objdump ,它可以反汇编程序,转储数据部分和更多!

我希望这回答你的问题…