字符串文字的C优化

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

等效词的字符串指针是相同的,我感到非常惊讶。我本以为每个字符串都会在堆栈上分配自己的内存,而不管它是否与另一个数组中的字符串相同。


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


天涯尽头无女友
浏览 468回答 3
3回答

慕无忌1623718

它称为“字符串池”。在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';

倚天杖

(我假设你a,b,c并d声明为局部变量,这是你的筹码相关预期的原因。)C中的字符串文字具有静态存储持续时间。它们永远不会被“分配”在栈上。它们始终分配在全局/静态存储器中,并且“永远存在”,即只要程序运行即可。您a,b,c和d数组被分配在堆栈中。存储在这些数组中的指针指向静态内存。在这种情况下,相同单词的指针相同并没有什么异常。编译器是否将相同的文字合并为一个取决于编译器。一些编译器甚至具有控制此行为的选项。字符串文字始终是只读的(这就是为什么最好const char *在数组中使用类型的原因),因此,在您开始依赖实际指针值之前,是否合并它们不会有太大的区别。PS只是出于好奇:即使将这些字符串文字分配在堆栈上,您为什么也希望相同的文字多次被“实例化”?

阿波罗的战车

据我所知,对同一字符串文字的两个(或更多)引用必须解析为相同的内存位置。即使有些是“重复的”,编译器也可以(有些确实)为每个字符串文字分配存储空间。
打开App,查看更多内容
随时随地看视频慕课网APP