c++常用对象内存布局

发布于:2025-08-18 ⋅ 阅读:(14) ⋅ 点赞:(0)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

提示:这里可以添加本文要记录的大概内容:

环境
linux内核5.10.92
x86平台
gcc gcc version 10.3.1 (GCC)
g++ gcc version 10.3.1 (GCC)


提示:以下是本篇文章正文内容,下面案例可供参考

一、c++常用对象介绍?

string
std::string 是一个专门用于处理文本字符串的类模板(特化自 std::basic_string)。它极大地简化了 C 风格字符串(以 \0 结尾的字符数组)的操作。
自动内存管理:无需手动 malloc/free 或 new/delete。
边界安全:提供 size(), length(), at() 等方法,避免缓冲区溢出。
丰富的操作:内置连接、查找、替换、比较等操作。
可变长度:可以动态增长或缩小。
与 STL 兼容:可以轻松地在算法和容器中使用。
vector
std::vector 是一个动态数组容器。它可以存储任意类型的对象(基本类型、类、甚至其他容器),并能自动管理其大小。
动态大小:可以在运行时添加或删除元素。
自动内存管理:自动分配和释放内存。
安全性:提供 size(), empty(), at() 等安全访问方式。
STL 兼容性:与算法(如 sort, find)完美配合。
RAII:遵循资源获取即初始化原则,避免内存泄漏

二、使用步骤

1.对象string

代码如下(示例):

// filename: test_string_layout.cpp
#include <iostream>
#include <string>
#include <cstring>
#include <iomanip>

// ✅ 新增:dump std::string 对象本身的二进制内容(32字节)
void dumpStringObject(const std::string& s, const std::string& label) {
    std::cout << "=== DUMP: " << label << " ===" << std::endl;
    std::cout << "String object at: " << (void*)&s << std::endl;
    std::cout << "sizeof(string) = " << sizeof(s) << " bytes" << std::endl;

    // 获取对象的原始字节
    const unsigned char* bytes = reinterpret_cast<const unsigned char*>(&s);
    std::cout << "Object memory dump (hex):" << std::endl;
    for (size_t i = 0; i < sizeof(s); ++i) {
        std::cout << std::setfill('0') << std::setw(2)
                  << std::hex << (int)bytes[i] << " ";
        if ((i + 1) % 8 == 0) std::cout << std::endl;
    }
    if (sizeof(s) % 8 != 0) std::cout << std::endl;
    std::cout << std::dec; // 回到十进制
}

// 原来的打印函数(保留)
void printStringInfo(const std::string& s, const std::string& label) {
    std::cout << "=== " << label << " ===" << std::endl;
    std::cout << "obj Size: " << sizeof(s) << std::endl;
    std::cout << "String object address: " << (void*)&s << std::endl;
    std::cout << "Size: " << s.size() << std::endl;
    std::cout << "Capacity: " << s.capacity() << std::endl;
    std::cout << "Data ptr: " << (void*)s.data() << std::endl;
    std::cout << "C-string ptr: " << (void*)s.c_str() << std::endl;
    std::cout << "Content: \"" << s << "\"" << std::endl;

    // 打印从 data() 指针开始的前 capacity + 1 个字节
    const char* data = s.data();
    std::cout << "Memory dump (hex): ";
    for (size_t i = 0; i <= s.capacity(); ++i) {
        printf("%02x ", (unsigned char)data[i]);
    }
    std::cout << std::endl;

    // 显示空终止符 \0 的位置
    const char* cstr = s.c_str();
    size_t null_pos = std::strlen(cstr);
    std::cout << "\\0 position (from c_str): " << null_pos << " (value: " << (int)cstr[null_pos] << ")" << std::endl;
    std::cout << std::endl;
}

int main() {
    // --- 1. 短字符串(SSO)---
    std::string s1 = "Hello";
    dumpStringObject(s1, "Short string (SSO)");
    printStringInfo(s1, "Short string (SSO?)");

    // --- 2. 长字符串(堆)---
    std::string s2 = "This is a longer string that will likely exceed SSO threshold.";
    dumpStringObject(s2, "Long string (heap)");
    printStringInfo(s2, "Long string (heap)");

    // --- 3. 空字符串 ---
    std::string s3;
    dumpStringObject(s3, "Empty string");
    printStringInfo(s3, "Empty string");

    // --- 4. 预留容量的字符串 ---
    std::string s4;
    s4.reserve(50);
    s4 = "Reserved";
    dumpStringObject(s4, "String with reserved capacity");
    printStringInfo(s4, "String with reserved capacity");

    return 0;
}


输出如下

[root@localhost ~]# ./a.out
=== DUMP: Short string (SSO) ===
String object at: 0x7ffc6e85fb90
sizeof(string) = 32 bytes
Object memory dump (hex):
a0 fb 85 6e fc 7f 00 00
05 00 00 00 00 00 00 00
48 65 6c 6c 6f 00 00 00
00 00 00 00 00 00 00 00
=== Short string (SSO?) ===
obj Size: 32
String object address: 0x7ffc6e85fb90
Size: 5
Capacity: 15
Data ptr: 0x7ffc6e85fba0
C-string ptr: 0x7ffc6e85fba0
Content: "Hello"
Memory dump (hex): 48 65 6c 6c 6f 00 00 00 00 00 00 00 00 00 00 00
\0 position (from c_str): 5 (value: 0)

=== DUMP: Long string (heap) ===
String object at: 0x7ffc6e85fb70
sizeof(string) = 32 bytes
Object memory dump (hex):
e0 52 b8 01 00 00 00 00
3e 00 00 00 00 00 00 00
3e 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
=== Long string (heap) ===
obj Size: 32
String object address: 0x7ffc6e85fb70
Size: 62
Capacity: 62
Data ptr: 0x1b852e0
C-string ptr: 0x1b852e0
Content: "This is a longer string that will likely exceed SSO threshold."
Memory dump (hex): 54 68 69 73 20 69 73 20 61 20 6c 6f 6e 67 65 72 20 73 74 72 69 6e 67 20 74 68 61 74 20 77 69 6c 6c 20 6c 69 6b 65 6c 79 20 65 78 63 65 65 64 20 53 53 4f 20 74 68 72 65 73 68 6f 6c 64 2e 00
\0 position (from c_str): 62 (value: 0)

=== DUMP: Empty string ===
String object at: 0x7ffc6e85fb50
sizeof(string) = 32 bytes
Object memory dump (hex):
60 fb 85 6e fc 7f 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
=== Empty string ===
obj Size: 32
String object address: 0x7ffc6e85fb50
Size: 0
Capacity: 15
Data ptr: 0x7ffc6e85fb60
C-string ptr: 0x7ffc6e85fb60
Content: ""
Memory dump (hex): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
\0 position (from c_str): 0 (value: 0)

=== DUMP: String with reserved capacity ===
String object at: 0x7ffc6e85fb30
sizeof(string) = 32 bytes
Object memory dump (hex):
30 53 b8 01 00 00 00 00
08 00 00 00 00 00 00 00
32 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
=== String with reserved capacity ===
obj Size: 32
String object address: 0x7ffc6e85fb30
Size: 8
Capacity: 50
Data ptr: 0x1b85330
C-string ptr: 0x1b85330
Content: "Reserved"
Memory dump (hex): 52 65 73 65 72 76 65 64 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
\0 position (from c_str): 8 (value: 0)

可以看出string对象布局:
sizeof大小 32
小于16长度的存储在栈上,大于存放在堆上。
obj:
8:指针指向字符串 栈或堆
8:字符串实际长度
8:长度小于16存储字符串,大于16存储堆上分配的大小
8:长度小于16存储字符串

ida中在函数中识别有地址是64[4],或者大小为20h,并且操作字符串,的可能就是string

2.对象vector

代码如下(示例):

[root@localhost ~]# cat test_c++_vector.cpp
// filename: test_vector_dump_object.cpp
#include <iostream>
#include <vector>
#include <iomanip>
#include <cstring>

// 打印 vector 对象本身的二进制内容(24 字节)
void dumpVectorObject(const std::vector<int>& v, const std::string& label) {
    std::cout << "=== DUMP: " << label << " ===" << std::endl;
    std::cout << "Vector object at: " << (void*)&v << std::endl;
    std::cout << "sizeof(vector<int>) = " << sizeof(v) << " bytes" << std::endl;

    // 获取对象的原始字节
    const unsigned char* bytes = reinterpret_cast<const unsigned char*>(&v);
    std::cout << "Object memory dump (hex):" << std::endl;
    for (size_t i = 0; i < sizeof(v); ++i) {
        std::cout << std::setfill('0') << std::setw(2)
                  << std::hex << (int)bytes[i] << " ";
        if ((i + 1) % 8 == 0) std::cout << std::endl;
    }
    if (sizeof(v) % 8 != 0) std::cout << std::endl;
    std::cout << std::dec; // 回到十进制
}

// 原来的打印函数(略作简化)
void printVectorPointers(const std::vector<int>& v, const std::string& label) {
    std::cout << "=== " << label << " ===" << std::endl;
    std::cout << "Vector object addr: " << (void*)&v << std::endl;
    std::cout << "sizeof(std::vector<int>) = " << sizeof(std::vector<int>) << " bytes" << std::endl;
    std::cout << "Size: " << v.size() << ", Capacity: " << v.capacity() << std::endl;

    if (v.empty()) {
        std::cout << "Data pointer: (null)" << std::endl;
        std::cout << std::endl;
        return;
    }

    const int* start = v.data();
    const int* finish = start + v.size();
    const int* end_of_storage = start + v.capacity();

    std::cout << "start           : " << (void*)start << std::endl;
    std::cout << "finish          : " << (void*)finish << std::endl;
    std::cout << "end_of_storage  : " << (void*)end_of_storage << std::endl;

    std::cout << "Element addresses and values:" << std::endl;
    for (size_t i = 0; i < v.size(); ++i) {
        std::cout << "  v[" << std::setw(2) << i << "] at "
                  << std::setw(14) << (void*)&v[i]
                  << " = " << std::setw(4) << v[i];
        if (i == 0) std::cout << "  <- start";
        std::cout << std::endl;
    }
    std::cout << std::endl;
}

int main() {
    // --- 1. 空 vector ---
    std::vector<int> v0;
    dumpVectorObject(v0, "Empty vector");
    printVectorPointers(v0, "Case 1: Empty vector");

    // --- 2. 小 vector(3个元素)---
    std::vector<int> v1 = {10, 20, 30};
    dumpVectorObject(v1, "Small vector (size=3)");
    printVectorPointers(v1, "Case 2: Small vector (size=3)");

    // --- 3. 预留容量但未填满 ---
    std::vector<int> v2;
    v2.reserve(10);
    v2 = {1, 2, 3};
    dumpVectorObject(v2, "Reserved capacity (cap=10)");
    printVectorPointers(v2, "Case 3: Reserved capacity (capacity=10, size=3)");

    // --- 4. 大 vector(多次扩容)---
    std::vector<int> v3;
    v3.reserve(1); // 强制从最小容量开始
    for (int i = 0; i < 5; ++i) {
        v3.push_back(i * 100);
    }
    dumpVectorObject(v3, "Large vector (size=5)");
    printVectorPointers(v3, "Case 4: Large vector (size=5)");

    return 0;
}

输出如下:

[root@localhost ~]# ./test_vector
=== DUMP: Empty vector ===
Vector object at: 0x7ffc4fae7b40
sizeof(vector<int>) = 24 bytes
Object memory dump (hex):
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
=== Case 1: Empty vector ===
Vector object addr: 0x7ffc4fae7b40
sizeof(std::vector<int>) = 24 bytes
Size: 0, Capacity: 0
Data pointer: (null)

=== DUMP: Small vector (size=3) ===
Vector object at: 0x7ffc4fae7b20
sizeof(vector<int>) = 24 bytes
Object memory dump (hex):
c0 72 82 01 00 00 00 00
cc 72 82 01 00 00 00 00
cc 72 82 01 00 00 00 00
=== Case 2: Small vector (size=3) ===
Vector object addr: 0x7ffc4fae7b20
sizeof(std::vector<int>) = 24 bytes
Size: 3, Capacity: 3
start           : 0x18272c0
finish          : 0x18272cc
end_of_storage  : 0x18272cc
Element addresses and values:
  v[00] at 000000x18272c0 = 0010  <- start
  v[01] at 000000x18272c4 = 0020
  v[02] at 000000x18272c8 = 0030

=== DUMP: Reserved capacity (cap=10) ===
Vector object at: 0x7ffc4fae7b00
sizeof(vector<int>) = 24 bytes
Object memory dump (hex):
00 73 82 01 00 00 00 00
0c 73 82 01 00 00 00 00
28 73 82 01 00 00 00 00
=== Case 3: Reserved capacity (capacity=10, size=3) ===
Vector object addr: 0x7ffc4fae7b00
sizeof(std::vector<int>) = 24 bytes
Size: 3, Capacity: 10
start           : 0x1827300
finish          : 0x182730c
end_of_storage  : 0x1827328
Element addresses and values:
  v[00] at 000000x1827300 = 0001  <- start
  v[01] at 000000x1827304 = 0002
  v[02] at 000000x1827308 = 0003

=== DUMP: Large vector (size=5) ===
Vector object at: 0x7ffc4fae7ae0
sizeof(vector<int>) = 24 bytes
Object memory dump (hex):
30 73 82 01 00 00 00 00
44 73 82 01 00 00 00 00
50 73 82 01 00 00 00 00
=== Case 4: Large vector (size=5) ===
Vector object addr: 0x7ffc4fae7ae0
sizeof(std::vector<int>) = 24 bytes
Size: 5, Capacity: 8
start           : 0x1827330
finish          : 0x1827344
end_of_storage  : 0x1827350
Element addresses and values:
  v[00] at 000000x1827330 = 0000  <- start
  v[01] at 000000x1827334 = 0100
  v[02] at 000000x1827338 = 0200
  v[03] at 000000x182733c = 0300
  v[04] at 000000x1827340 = 0400


可以看出vector对象布局:



总结

上面介绍了linux c++的string和vector的内存布局情况。


网站公告

今日签到

点亮在社区的每一天
去签到