【问题标题】:C optimisation of string literals字符串文字的 C 优化
【发布时间】:2012-07-09 02:59:46
【问题描述】:

我刚刚在 gdb 中检查了以下内容:

char *a[] = {"one","two","three","four"};
char *b[] = {"one","two","three","four"};
char *c[] = {"two","three","four","five"};
char *d[] = {"one","three","four","six"};

...我得到以下信息:

(gdb) p a
$17 = {0x80961a4 "one", 0x80961a8 "two", 0x80961ac "three", 0x80961b2 "four"}
(gdb) p b
$18 = {0x80961a4 "one", 0x80961a8 "two", 0x80961ac "three", 0x80961b2 "four"}
(gdb) p c
$19 = {0x80961a8 "two", 0x80961ac "three", 0x80961b2 "four", 0x80961b7 "five"}
(gdb) p d
$20 = {0x80961a4 "one", 0x80961ac "three", 0x80961b2 "four", 0x80961bc "six"}

我真的很惊讶字符串指针对于等价词是相同的。我原以为每个字符串都会在堆栈上分配自己的内存,而不管它是否与另一个数组中的字符串相同。

这是某种编译器优化的例子,还是这种字符串声明的标准行为?

【问题讨论】:

  • 这个问题中的“堆栈”是从哪里来的?如果您将abcd 声明为局部变量,您必须在问题中这样说。
  • 是的 - 它们是在函数内声明的自动持续时间的局部变量,因此在堆栈中
  • 是的。这是一个编译器优化的例子。
  • 怎么样? - 这只是我误解了 C 如何存储字符串文字,上面来自@legends2k 的链接对于解释实际发生的事情非常有用

标签: c string gcc compiler-optimization string-pool


【解决方案1】:

这被称为“字符串池”。它在 Microsoft 编译器中是可选的,但在 GCC 中不是。如果您在 MSVC 中关闭字符串池,那么不同数组中的“相同”字符串将被复制,并且具有不同的内存地址,因此会占用额外(不必要的)50 字节左右的静态数据。

编辑:v 4.0 之前的 gcc 有一个选项,-fwritable-strings,它禁用了字符串池。此选项的效果是双重的:它允许覆盖字符串文字,并禁用字符串池。因此,在您的代码中,设置此标志将允许一些危险的代码

/* Overwrite the first string in a, so that it reads 'xne'.  Does not */ 
/* affect the instances of the string "one" in b or d */
*a[0] = 'x';

【讨论】:

  • 在 GCC(至少 4.7)中,禁用池的开关是 -fno-merge-constants。
  • @dbrank0 请注意gcc no longer supports fwritabe-srings,最好将这两个注释都添加到您的答案中。
【解决方案2】:

(我假设您的 abcd 被声明为局部变量,这是您与堆栈相关的期望的原因。)

C 中的字符串文字具有静态存储持续时间。它们永远不会在“堆栈上”分配。它们总是分配在全局/静态内存中并且“永远”存在,即只要程序运行。

您的 abcd 数组已分配在堆栈上。存储在这些数组中的指针指向静态内存。在这种情况下,相同单词的指针相同并没有什么不寻常的。

编译器是否会将相同的文字合并为一个取决于编译器。一些编译器甚至有一个选项来控制这种行为。字符串文字始终是只读的(这就是为什么对数组使用 const char * 类型是一个更好的主意),因此在您开始依赖实际指针之前,它们是否被合并并没有太大区别价值观。

附:只是出于好奇:即使这些字符串文字是在堆栈上分配的,为什么您会期望相同的文字被多次“实例化”?

【讨论】:

  • 很棒的东西——这对我的理解有很大帮助,还没有完全理解字符串文字的东西及其相关的存储持续时间——我错误地认为字符串只是局部变量(自动)堆栈
  • 我所知道的没有任何内容表明对同一字符串文字的两个(或多个)引用必须解析到相同的内存位置。编译器可以(并且有些确实)为每个字符串文字分配存储空间,即使有些是“重复的”。请参阅@Josh 提到的“字符串池”。
猜你喜欢
  • 2010-09-22
  • 2017-06-10
  • 2017-07-10
  • 2010-09-21
  • 1970-01-01
  • 2012-07-28
  • 2011-08-20
  • 2019-12-04
相关资源
最近更新 更多