【C++开发教程】C++内存中的字符串
小职 2021-09-08 来源 :「Golang In Memory」 阅读 641 评论 0

摘要:本文主要介绍了【C++开发教程】C++内存中的字符串,通过具体的内容向大家展现,希望对大家C++开发的学习有所帮助。

本文主要介绍了【C++开发教程】C++内存中的字符串,通过具体的内容向大家展现,希望对大家C++开发的学习有所帮助。

【C++开发教程】C++内存中的字符串

研究的是C++字符串在内存中的结构。

 

环境

1. 操作系统:Ubuntu 16.04。

2. 调试软件:GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1。

3. 编译工具:g++ (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609。

string类的定义

string定义在/usr/include/c++/5/bits/stringfwd.h头文件中,如下:

 

 

typedef basic_string<char> string;

basic_string类的定义通过泛型编程技术实现,详细定义请参考/usr/include/c++/5/bits/basic_string.h头文件,看起来非常复杂,具体实现此处并不关心,不再讨论。

 

测试string对象占用内存空间

通过以下代码可以测试string类对象占用内存空间情况。

 

 

// demo.cpp

#include <string>

#include <iostream>

 

int main(int argc, char const *argv[])

{

    using namespace std;

 

    string s15(15, 'a'); // 字符串长度15

    string s16(16, 'x'); // 字符串长度16

     

    cout << "sizeof(string) = " << sizeof(string) << endl;

    cout << "sizeof(s15) = " << sizeof(s15) << endl;

    cout << "sizeof(s16) = " << sizeof(s16) << endl;

 

    return 0;

}

因为32位和64位可执行程序不同,以下将分别编译测试。

 

将以上代码编译成32位可执行程序并执行,结果如下:

$ g++ -m32 -g demo.cpp

$ ./a.out  

sizeof(string) = 24

sizeof(s15) = 24

sizeof(s16) = 24

从以上输出结果,可以十分确定string类对象在内存中占用24个字节。

 

将以上代码编译成64位可执行程序并执行,结果如下:

$ g++ -m64 -g demo.cpp

$ ./a.out

sizeof(string) = 32

sizeof(s15) = 32

sizeof(s16) = 32

从以上输出结果,可以十分确定string类对象在内存中占用32个字节。

 

32位可执行程序string对象的内存分配

为了查看内存分配,需要用到动态调试工具,此处使用gdb,并在源码16行设置断点。

 

调试过程中,打印main方法的栈数据,以及string对象及相关数据的内存,可以清晰看到string对象数据的内存占用情况。

 

 

$ gdb a.out  

GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1

Reading symbols from a.out...done.

(gdb) b 16

Breakpoint 1 at 0x8048a80: file demo.cpp, line 16.

(gdb) r

Starting program: a.out  

sizeof(string) = 24

sizeof(s15) = 24

sizeof(s16) = 24

 

Breakpoint 1, main (argc=1, argv=0xffffced4) at demo.cpp:16

16      return 0;

(gdb) x /24wx $esp  // 以16进制格式打印24个宽度为4字节的main函数堆栈数据(共96个字节)

0xffffcdd0:  0x08048790  0x0804a0ed  0x0804a04c  0xffffced4

0xffffcde0:  0xffffffff  0x00004a00  0xffffce08  0xffffcdf4

0xffffcdf0:  0x0000000f  0x61616161  0x61616161  0x61616161

0xffffce00:  0x00616161  0x0804fa10  0x00000010  0x00000010

0xffffce10:  0x00000001  0xffffced4  0xffffcedc  0xd0415500

0xffffce20:  0xffffce40  0x00000000  0x00000000  0xf7c86637

(gdb) x /wx &s15    // 打印变量s15的内存地址

0xffffcdec:  0xffffcdf4

(gdb) x /6xw 0xffffcdec // 打印string对象s15占用的24个字节内存数据

0xffffcdec:  0xffffcdf4  0x0000000f  0x61616161  0x61616161

0xffffcdfc:  0x61616161  0x00616161

(gdb) x /s 0xffffcdf4   // string对象s15的1-4个字节是一个指向字符数据的指针

0xffffcdf4:  'a' <repeats 15 times>

(gdb) x /16x 0xffffcdf4 // string对象s15的9-24个字节是代表数据的字符数组

0xffffcdf4:  0x61  0x61  0x61  0x61  0x61  0x61  0x61  0x61

0xffffcdfc:  0x61  0x61  0x61  0x61  0x61  0x61  0x61  0x00

(gdb) x /wx &s16    // 打印变量s16的内存地址

0xffffce04:  0x0804fa10

(gdb) x /6xw 0xffffce04 // 打印string对象s16占用的24个字节内存数据

0xffffce04:  0x0804fa10  0x00000010  0x00000010  0x00000001

0xffffce14:  0xffffced4  0xffffcedc

(gdb) x /s 0x0804fa10  // string对象s16的1-4个字节是一个指向字符数据的指针

0x804fa10:  'x' <repeats 16 times>

(gdb) x /16x 0x0804fa10

0x804fa10:  0x78  0x78  0x78  0x78  0x78  0x78  0x78  0x78

0x804fa18:  0x78  0x78  0x78  0x78  0x78  0x78  0x78  0x78

(gdb) c

Continuing.

[Inferior 1 (process 20982) exited normally]

(gdb) q

从以上调试可以看出,string对象的内存结构和以下结构体的非常相似:

 

typedef long int u32;

struct String

{

    char *data_ptr; // 指向字符数组的指针,在32位程序占用4个字节

    u32 length;     // 字符数组的长度,在32位程序占用4个字节

    char data[16];  // 可以容纳15个字符的数组,占用16个字节

};

1.string对象的1-4个字节是一个指向字符数据的指针。

 

2.string对象的5-8个字节是一个表示字符数据长度的整形数值。

 

3.string对象的9-24个字节的含义根据字符数据的长度发生变化。

 

如果string对象包含的字符数组长度小于16,则将字符数据保存在string对象本身所占用的内存中;以上述结构体String为例,将字符数据保存在data中。

s15.data_ptr == &(s15.data[0]);

如果string对象包含的字符数组长度大于等于16,则其字符数据位于可执行文件的数据区或分配到堆内存中,而不是栈内存中;以上述结构体String为例,无法将字符数据保存在data字段中。

64位可执行程序string对象的内存分配

64位程序与32位程序非常相似,只不过64程序中,指针对象占用8字节内存;通过动态调试,发现内存分配与以下结构体非常相似:

 

typedef long long int u64;

struct String

{

    char *data_ptr; // 指向字符数组的指针,在64位机器占用8个字节

    u64 length;     // 字符数组的长度,在64位机器占用8个字节

    char data[16];  // 可以容纳15个字符的数组,占用16个字节

};

以上内容是两年多前的学习笔记,最近在以下环境中进行测试,得到的结论与上述内容一致。

 

操作系统:Ubuntu 20.04。

调试软件:GNU gdb (Ubuntu 9.2-0ubuntu1~20.04) 9.2。

编译工具:g++ (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0。



我是小职,记得找我

✅ 解锁高薪工作

✅ 免费获取基础课程·答疑解惑·职业测评

【C++开发教程】C++内存中的字符串

本文由 @小职 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程