当我编译并运行我的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
,它可以反汇编程序,转储数据部分和更多!
我希望这回答你的问题…