【问题标题】:Is declaring a string literal with a pointer more memory efficient than declaring constant array?使用指针声明字符串文字是否比声明常量数组更节省内存?
【发布时间】:2017-01-29 10:51:09
【问题描述】:

如果我想存储一个常量字符串,

const char array[] = "Some string literal.";

C 入门加书说

然后引用的字符串存储在作为可执行文件一部分的数据段中。只有在程序开始运行后才会为数组分配内存。此时,引用的字符串被复制到数组中。

这是否意味着为字符串文字分配了两次内存?

另一方面,当用指针声明时,它只为指针变量留出存储空间,并将字符串字面量的地址存储在其中。

const char *pt = "Some string literal.";

这意味着字符串文字只有一个副本,并且用字符串文字声明指针比数组更节省内存?

【问题讨论】:

  • “C 入门加书”(无论如何)对编译器的工作方式做出了不真实的概括——大概是基于 ONE 编译器的工作方式。该标准没有规定这些结构如何反映在可执行文件中,并且不同的编译器会做不同的事情(至少部分是因为不同的可执行格式允许以不同的方式完成事情)。
  • 替代品的“效率”应该与您无关。这些永远不会成为任何规模的瓶颈;如果您的问题不完全是学术性质的,那么您就陷入了过早优化的陷阱。
  • @Peter-- 如果你不了解这本书,我认为破坏某人对他们正在学习的书的信心是没有帮助的。 C Primer Plus 是第 6 版,我发现它并不完美,但非常好。我们不知道OP的版本,但在我的版本中,首先说“字符串常量放在静态存储类中”,然后说“通常......引用的字符串被存储在数据段中......”我不会称这是不真实的概括,但你可能有理由不同意。
  • 这一切都取决于实现细节。您可以检查您通常使用的实现会发生什么。这段代码是在块作用域还是文件作用域也有所不同。

标签: c pointers


【解决方案1】:

在第一种情况下,字符串的数据存储在可执行文件中,并在程序加载后存储在内存中。所以是的,它被“分配了两次”,但是在非常不同的存储介质(磁盘和内存)中。

但是,第二种情况也是如此。字符串文字需要在磁盘上的可执行文件中存储一次,在程序运行时在内存中存储一​​次。

区别在于实现细节,即在第一种情况下,内存中的字符串要么存储在堆栈上,要么存储在一些全局可修改的数据内存段中。在第二种情况下,字符串通常与代码一起存储。

所以如果你在第一种情况下只有一个字符串的实例,那么“内存效率”是没有区别的。

【讨论】:

  • 如何修改第一个字符串? array 被声明为 const char
  • @babon 哎呀,错过了。谢谢
【解决方案2】:

答案取决于定义出现在全局范围还是局部范围。

  • 在全球范围内:

    • 第一个选项定义一个初始化的常量数组。使用array[0] 从中读取字节将导致代码从全局内存位置读取单个字节,通常是单个指令。

    • 第二个选项定义了一个可修改的指针,初始化为指向一个常量字符数组。使用array[0]从中读取字节将导致代码加载指针值并读取指针指向的元素,通常至少有2条指令。

    如果您不需要更改 array 所指的字符串,则最好使用第一个选项。

  • 在本地范围内(自动存储)

    • 第一个选项定义了一个用字符串初始化的数组。如果这个数组不是常量并且在函数内部被修改,那么生成的代码将与此基本相似:

      char array[sizeof "Some string literal."];
      memcpy(array, "Some string literal.", sizeof(array));
      

      但由于它被定义为const,编译器可以优化代码并生成对array 的引用作为对静态存储中字符串文字的引用。为避免上述潜在代码生成,您可以在本地范围内使用此定义:

      static const char array[] = "Some string literal.";
      
    • 相反,第二个选项定义了一个初始化为指向字符串文字的本地指针,它本身很可能存储在静态存储中,例如数据段甚至代码段。如果该函数使用array,则该定义可以生成一个存储来初始化指针和或多或少的代码来从中读取字符,具体取决于函数内部的特定代码以及编译器的效率。

在全局范围内,使用第一种方法似乎更有效。

在本地范围内,它在很大程度上取决于使用的实际代码和编译器,但定义 static const char 数组可能是最有效的。

【讨论】:

  • 编译器处理函数本地字符串常量的方式存在显着差异。有些人会将其存储在函数外部的常量数据中,而另一些人甚至可能在指令中使用整数常量将小字符串保存在寄存器中。
猜你喜欢
  • 2015-05-21
  • 1970-01-01
  • 2011-04-01
  • 1970-01-01
  • 2012-04-04
  • 1970-01-01
  • 2012-10-22
  • 2019-03-01
  • 1970-01-01
相关资源
最近更新 更多