当前位置: 首页 > news >正文

从C语言变量看内存

1.1 变量的存储位置(内存区域)

C程序的内存布局通常分为以下几部分:
代码段(Text Segment):存储可执行指令(如函数代码)。只读,可被多个进程共享。

物理载体:通常存储在磁盘的可执行文件中,程序加载时被读入DDR内存(RAM)。

数据段(Data Segment 初始值存储在磁盘的可执行文件中,加载时复制到DDR内存。):
.data:初始化的全局变量和静态变量
.bss:初始化的全局变量和静态变量(程序启动时自动清零)。

(Heap):动态分配的内存(malloc/free)。物理载体:DDR内存中的动态区域。
(Stack):局部变量、函数参数等(自动分配/释放)。DDR内存中的连续区域(由CPU栈指针管理)。

1.2 存储类别修饰符与存储位置

  • static 修饰的变量
    存储位置:数据段(.data 或 .bss)。
    生命周期:整个程序运行期间。
    作用域:
    修饰全局变量:仅在当前文件内可见(限制作用域)。
    修饰局部变量:仅在函数内可见,但生命周期延长到程序结束。
    示例:

    static int x;          // 未初始化,存储在.bss
    static int y = 10;     // 已初始化,存储在.datavoid func() {static int count = 0; // 存储在.data,函数调用间保持值count++;
    }
    
  • volatile 修饰的变量
    存储位置:由变量定义的位置决定(如全局volatile在数据段,局部volatile在栈)。
    作用:告诉编译器不要优化对该变量的访问(每次从内存读取,防止缓存优化)。
    典型用途:硬件寄存器、多线程共享变量
    示例:

    volatile int *hw_reg = (volatile int*)0xFFFF0000; // 硬件寄存器地址
    volatile int flag = 0;
    while (flag == 0) {// 编译器不会优化为 if (flag == 0) while (true);// 每次循环都会从内存读取flag的值
    }
    
  • auto(默认修饰符)
    存储位置:栈(Stack)。
    生命周期:函数调用时创建,返回时释放
    示例:

    void func() {auto int x = 5; // 等同于 int x = 5;
    }
    
  • register(建议性修饰符)
    存储位置:尝试将变量存储在CPU寄存器(非内存),但由编译器决定。
    限制:不能取地址(**&**操作)。
    示例:

    register int i; // 建议编译器将i放入寄存器
    ;
    int* get_local_ptr() {int x = 10; // x在栈上return &x;  // 错误!函数返回后x的内存失效
    }
    
  • extern
    存储位置:声明外部已定义的变量(实际存储位置由定义决定)。
    作用:跨文件引用全局变量。
    示例:

    // file1.c
    int global_var = 42; // 存储在.data
    // file2.c
    extern int global_var; // 引用file1.c中的global_var
    
  • 堆栈

    int *p = malloc(100); // 从堆分配100字节,DDR内存中分配void func() {int x; // x在栈上分配(DDR内存)
    }
    

    当DDR内存不足时,操作系统将不活跃的内存页换出到磁盘交换区(Swap Space),需要时再换入。
    示例:若堆内存耗尽且无交换空间,malloc返回NULL。

1.3 数据类型与存储位置的关系

  • 基本数据类型(int、float等)
    存储位置:由修饰符决定:
    全局变量 → 数据段。
    局部变量 →
    static修饰 → 数据段

  • 指针类型(int*、char*等)
    存储位置:
    指针变量本身的位置由修饰符决定(如局部指针在栈)。
    指针指向的数据可能在任何区域(需结合malloc、全局变量等分析)。

  • 数组与结构体
    存储位置:
    全局数组/结构体 → 数据段。
    局部数组/结构体 → 栈。
    static修饰 → 数据段。

  • 动态分配的内存(malloc/free)
    存储位置:堆(Heap)。
    示例:

    int *arr = (int*)malloc(10 * sizeof(int)); // arr在栈,指向堆内存
    

1.4 典型问题

  • 为什么栈比堆快?
    栈通过CPU硬件指令(如push/pop)直接操作,而堆需要调用库函数(如malloc)并可能触发系统调用。
    栈内存地址连续,缓存命中率高;堆内存碎片化。

1.5 总结

修饰符/类型存储位置生命周期作用域
static数据段(.data/.bss)程序整个运行期文件内或函数内
volatile由定义位置决定同普通变量同普通变量
auto栈(Stack)函数调用期间函数内
registerCPU寄存器(可能)auto函数内
extern由定义决定程序整个运行期跨文件
动态内存堆(Heap)手动控制(free通过指针访问
磁盘(可执行文件)│├── 代码段(加载到DDR) → CPU执行└── 数据段(加载到DDR)├── .data(已初始化)└── .bss(未初始化,清零)DDR内存(运行时)├── 代码段(只读)├── 数据段├── 堆(动态分配)└── 栈(自动管理)

相关文章:

  • LX3-初识是单片机
  • java集合框架day1————集合体系介绍
  • mongodb 存储数据的具体实现方式
  • 基于SpringBoot的篮球联盟管理系统(源码+数据库+万字文档)
  • 如何开发一套TRS交易系统:架构设计、核心功能与风险控制
  • 第十三讲、isaaclab中修改工作流的RL环境
  • CCF CSP 第37次(2025.03)(1_数值积分_C++)
  • Java 程序员的 Python 之旅
  • 【线段树】P1253 扶苏的问题|普及+
  • 操作系统期中复习
  • 初识Redis · C++客户端list和hash
  • 第七届传智杯全国IT技能大赛程序设计赛道 国赛(总决赛)—— (B组)题解
  • 【PyQt5】@QtCore.pyqtSlot()的作用
  • oracle不同数据库版本的自增序列
  • element-ui中的上传组件el-upload非自动上传监听不到success
  • go for 闭环问题【踩坑记录】
  • DeepseekV3MLP 模块
  • 快充协议芯片XSP04D支持使用一个Type-C与电脑传输数据和快充取电功能
  • 腾讯一面-软件开发实习-PC客户端开发方向
  • LX4-数据手册相关
  • 上海之旅相册②俄罗斯Chaika:客居六年,致上海的情书
  • 马文化体验展商圈启动,环球马术冠军赛的能量不止在赛场
  • 人均300+的日料,是后厨拆开的预制料理包
  • 探索未来课堂更多可能,“人工智能课堂分析循证实验室”在沪成立
  • 龙登高谈近世的基层治理及制度变迁
  • 甘肃古浪县发生3.0级地震,未接到人员伤亡和财产损失报告