C/C++ 中每个字符串都以字符 \0 作为结尾,以此作为字符串结束的标志。
为了节省内存,C/C++ 把常量字符串放到单独的一个区域(一般放置在.rodata 中)。当几个指针赋值给相同的常量字符串时,它们实际上会指向相同的内存地址,因为在内存中,只存在一份相同的常量字符串。
.rodata区域一般用来放置只读数据,如常量字符串,const修饰的变量等(也有的编译器将常量字符串放在.data中)
下面是一道常见的面试题(本人就遇到过),略做了修改:
int main(int argc, char *argv[]) {
char str1[] = "hello world";
char str2[] = "hello world";
// 如果直接 cout << str1 ; 或者 cout << (char *)str1 ;
// 则输出的是数组的内容,而不是数组的地址
cout << (void *)str1 << endl;
cout << (void *)str2 << endl; // 输出数组的首地址
cout << endl;
const char *str3 = "hello world";
const char *str4 = "hello world";
cout << (void *)("hello world") << endl; // 输出常量字符串的地址
cout << (void *)str3 << endl;
cout << (void *)str4 << endl;
cout << endl;
if (str1 == str2)
printf("str1 and str2 are same.\n");
else
printf("str1 and str2 are not same.\n");
if (str3 == str4)
printf("str3 and str4 are same.\n");
else
printf("str3 and str4 are not same.\n");
return 0;
}
在 gcc 7.3.0 中运行的结果为:
0x7fff49fcfbd0
0x7fff49fcfbdc
0x557768a2ebc5
0x557768a2ebc5
0x557768a2ebc5
str1 and str2 are not same.
str3 and str4 are same.
解析:str1 和 str2 是两个字符串数组,编译器会为它们分配两个长度为 12 字节的空间(在栈空间中),并把 “hello world” 的内容分别复制到数组中去,即使 str1 和 str2 前面有 const 修饰,结果也是这样,即这是两个初始地址不同的数组,str1 和 str2 的值当然不一样,但是数组里的内容是一样的。
代码中出现的所有 “hello world” 在内存中其实只存在一份(可通过 objdump -s 查看)。编译器将所有相同的常量字符串在 .rodata 中只保存其一份实体,但是可以在程序中存在多个不同名称的指针去指向它,但是那些指针变量里所存的内容却是一样的(指针变量本身的地址不同),存的都是这个相同的常量字符串中所在内存的地址。所以 str3 和 str4 的值是相同的。
通过 objdump 工具可以证实上面所述,执行 objdump -s a.out 命令:
...
Contents of section .rodata:
0bc0 01000200 0068656c 6c6f2077 6f726c64 .....hello world
0bd0 00737472 3120616e 64207374 72322061 .str1 and str2 a
0be0 7265206e 6f742073 616d652e 00737472 re not same..str
0bf0 3320616e 64207374 72342061 72652073 3 and str4 are s
0c00 616d652e 00737472 3320616e 64207374 ame..str3 and st
0c10 72342061 7265206e 6f742073 616d652e r4 are not same.
0c20 00
...
从上面的结果可以得知,所有的常量字符串都存储在 .rodata 中,而且相同的常量字符串只存在一份。
常量字符串 的类型为 const char *,是一个字符数组。
cout << typeid(“hello world”).name() << endl; // A12_c
cout << typeid(str3).name() << endl; // PKc
本文探讨了C/C++中字符串的存储方式,特别是如何利用.rodata区域来存放常量字符串,实现内存优化。通过一个示例程序展示了相同字符串常量在内存中的唯一性和指针引用的一致性。
8117

被折叠的 条评论
为什么被折叠?



