字符串文字的C优化

时间:2012-07-09 16:56:13

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

刚刚在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"}

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

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

2 个答案:

答案 0 :(得分:27)

它被称为“字符串池”。它在Microsoft Compilers中是可选的,但在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';

答案 1 :(得分:8)

(我假设您的abcd被声明为本地变量,这是您与堆栈相关的期望的原因。)< / p>

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

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

编译器是否将相同的文字合并为一个取决于编译器。有些编译器甚至有一个控制此行为的选项。字符串文字总是只读的(这就是为什么最好为你的数组使用const char *类型),所以它们是否合并没有多大区别,直到你开始依赖实际指针值。

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