C/C++ 程序内存分区详解:从实验到工具验证


📜 C/C++ 程序内存分区详解:从实验到工具验证


1. 内存分区概述

程序运行时,内存被划分为多个逻辑区,各司其职:

  • 代码区(Text):存储可执行指令,只读
  • .rodata 段:存储只读数据(如字符串字面量 “Hello” 和 const 全局变量)。
  • Data段:存储已初始化的全局变量和静态变量(如 int global = 42;)。
  • BSS段:存储未初始化的全局变量和静态变量(默认初始化为 0)。
  • 堆区(Heap):动态分配的内存(malloc/new),需手动管理。
  • 栈区(Stack):存储局部变量和函数参数,自动管理。

2. 实验验证内存布局

通过代码打印变量地址,结合工具验证存储位置:

//basestore.c
#include <stdio.h>
#include <stdlib.h>

// 已初始化的全局变量 → Data段
int global_init = 42;

// 未初始化的全局变量 → BSS段
int global_uninit;

// const常量 → .rodata(只读)
const int global_const = 100;

int main() {
    // 局部变量 → 栈区
    int local_stack = 5;

    // 动态分配内存 → 堆区
    int *heap_var = (int*)malloc(sizeof(int));

    printf("全局初始化变量地址: %p\n", &global_init);
    printf("全局未初始化变量地址: %p\n", &global_uninit);
    printf("全局常量地址: %p\n", &global_const);
    printf("栈变量地址: %p\n", &local_stack);
    printf("堆变量地址: %p\n", heap_var);

    free(heap_var);
    return 0;
}

运行结果

全局常量地址: 0x5561d8ffc008  (.rodata)
Data段地址: 0x5561d8ffe010     (Data段)
BSS段地址: 0x5561d8ffe018      (BSS段)
栈变量地址: 0x7ffcd9f56dac     (栈区)
堆变量地址: 0x55620cf8b2a0     (堆区)

3. 内存布局示意图
高地址
┌───────────────────┐
│      栈区          │ ← 向下增长(局部变量)
├───────────────────┤
│      堆区          │ ← 向上增长(动态分配)
├───────────────────┤
│      BSS段         │ ← 未初始化全局变量(默认0)
├───────────────────┤
│      Data段        │ ← 已初始化全局变量
├───────────────────┤
│     .rodata段      │ ← 全局常量(只读)
├───────────────────┤
│      代码区         │ ← 可执行指令
低地址

4. 工具验证:nm、size、objdump
(1) 使用 nm 查看符号表
nm -n basestore | grep "global_"

输出:

0000000000002008 R global_const   # .rodata
0000000000004010 D global_init    # Data段
0000000000004018 B global_uninit  # BSS段
  • 符号类型
    • R → 只读数据段(.rodata)。
    • D → 已初始化数据段(Data)。
    • B → 未初始化数据段(BSS)。
(2) 使用 size 查看段大小
size basestore

输出:

text    data     bss     dec     hex filename
2186     628      12    2826     b0a basestore
  • Data段:628 字节(包含用户变量和编译器内部数据)。
  • BSS段:12 字节(仅用户变量占 4 字节)。
(3) 使用 objdump 查看Data段内容
objdump -s -j .data basestore

输出:

basestore:     file format elf64-x86-64

Contents of section .data:
 4000 00000000 00000000 08400000 00000000  .........@......
 4010 2a000000                             *...      

十六进制值 0x2a → 十进制 42(global_init的值)

5. 关键结论
  1. 内存分区顺序:代码区 → .rodata → Data → BSS → 堆 → 栈。
  2. Data与BSS地址接近:用户变量少,段总大小由编译器内部数据主导。
  3. 只读段保护:尝试修改 .rodata 会触发段错误。
  4. 工具验证nmsizeobjdump 是分析内存布局的利器。

6. 一句话总结

内存分区各司其职:代码只读,Data存初值,BSS省空间,堆手动管,栈自动清!


动手实验:尝试修改代码,添加更多变量,观察地址变化,加深理解! 🔍

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值