当我在由GCC编译的Linux x86_64计算机上编译并运行以下C程序时:
#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
我知道字符串存储在常量表中,但是与动态分配的内存相比,地址太低了。
与以下程序比较:
#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如何为这两个程序生成代码,以及它们在执行过程中如何映射到内存。由于已经将其记录在文档中,因此很多时候都欢迎使用任何指向文档的链接。
在这两种情况下,编译器在程序部分"hello"仅发出一次字符串的实际字节.rodata( rodata 代表 只读数据 )。
"hello"
.rodata
它们实际上是直接从可执行文件映射到内存的,有点类似于代码部分。这就是为什么它们与动态分配的相距甚远的原因。
然后:
char *p = "hello";
只需将其初始化p为该(只读)数据的地址。显然:
p
char *q = "hello";
获取完全相同的地址。这称为 字符串池 ,是编译器的可选流行优化。
但是当你写:
char p[] = "hello";
它可能会生成如下内容:
char p[6]; memcpy(p, "hello", 6);
作为"hello"只读汇集字符串的实际地址。
的调用memcpy仅出于说明目的。最好直接内联复制,而不是使用函数调用。
memcpy
如果以后再做:
char q[] = "hello";
它将定义另一个数组和另一个数组memcpy()。因此,相同的数据,但不同的地址。
memcpy()
但是这些数组变量将驻留在哪里?好吧,这取决于。
.data
main
variables of static duration
关于文档链接,对不起,我一无所知。
但是,如果您可以自己进行实验,谁需要文档?为此,最好的工具是objdump,它可以反汇编程序,转储数据节等等!
objdump
我希望这能回答您的问题…