当前位置: 首页 > 面试题库 >

GCC将字符串常量存储在哪里以及这些指针从何处映射?

郭胤
2023-03-14
问题内容

当我在由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"仅发出一次字符串的实际字节.rodatarodata 代表 只读数据 )。

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

然后:

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,它可以反汇编程序,转储数据节等等!

我希望这能回答您的问题…



 类似资料:
  • 我正在学习虚拟内存和自由空间管理。 我知道我们使用malloc分配的指针将请求堆中的一块内存。但是当我们调用malloc()系统调用时,它将返回一个整数作为专用内存块的地址,但是这个地址本身将存储在哪里呢? 假设 返回我的4008地址。它从4008到4022开始。这个块在堆中。但是4008本身在哪里? 它存储在堆栈中吗?

  • 根据Java, 字符串存储在两个地方。字符串字面池和堆内存根据其创建。我需要知道,当字符串赋值到另一个字符串时,新创建的字符串将存储在哪里? 我对堆和字符串池中的字符串类型都进行了赋值操作。我得到了这样的结果。 但是当, 如果我这么做 同样地, 现在 以上是我在IDE上得到的输出。根据该输出,strNew的一个新引用对象在字符串池中创建,strNew的一个新引用对象在堆中创建。对吗?

  • 问题内容: 我在桌面应用程序中使用spring + hibernate。 我正在尝试使用分层实现来构建它,所以我有: GUI层–call- >服务层–call-> DAO层 一个更好地说明我的情况的小例子: 问题是:谁抛出异常并由谁处理? 我认为DAO必须抛出第一个异常,然后服务层将其抛出,最后GUI层处理该异常,这样我才能向用户显示消息,这很好吗?有没有一种方法可以使用spring构建一些Exc

  • 主要内容:到底使用字符数组还是字符串常量C语言中没有特定的字符串类型,我们通常是将字符串放在一个字符数组中,这在《 C语言字符数组和字符串》中已经进行了详细讲解,这里不妨再来演示一下: 运行结果: https://www.xnip.cn https://www.xnip.cn 字符数组归根结底还是一个数组,上节讲到的关于 指针和数组的规则同样也适用于字符数组。更改上面的代码,使用指针的方式来输出字符串: 运行结果: https://ww

  • 问题内容: 被存储在客户端或服务器上的变量? 问题答案: 变量存储的位置由PHP的配置确定。通常这是在Linux / Unix系统上。如果无法100%确定,请使用此功能查看您的特定设置,方法是在您域的中创建具有以下内容的文件:

  • 问题内容: 我是JAVA的初学者,我正在编写这段代码,该代码应该接收字符串数组并将每个字符串(数组元素)分别存储在指定的变量中。但是它仅存储第一个元素。下面是代码: 问题答案: