当前位置: 首页 > 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内存(运行时)├── 代码段(只读)├── 数据段├── 堆(动态分配)└── 栈(自动管理)
http://www.xdnf.cn/news/66169.html

相关文章:

  • BR_调制特性(RF/TRM/CA/BV-07-C [Modulation Characteristics])
  • [密码学基础]GB与GM国密标准深度解析:定位、差异与协同发展
  • 【C++】基于红黑树的map和set封装实现
  • 美信监控易:易用性卓越的智能运维管理平台
  • 详解机器学习各算法的优缺点!!
  • 算法——背包问题(分类)
  • DeepSeek与WPS的动态数据可视化图表构建
  • 2025 活体识别+人脸认证工具类【阿里云api,需要先申请试用】
  • NetApp ONTAP 9 故障磁盘更换操作指南
  • MySQL的窗口函数(Window Functions)
  • 实训Day-1 漏洞攻击实战
  • 【LeetCode 热题 100】哈希、双指针、滑动窗口
  • 【Markdown】【HTML】在Markdown中实现康奈尔笔记模式(右侧留白)
  • 算法分析与设计——动态规划复习题(待更新
  • Flutter 状态管理 Riverpod
  • 华为IPD流程变革如何推动组织转型?2025变革路径
  • 从代码实现理解Vision Permutator:WeightedPermuteMLP模型解析
  • Java并发编程-线程池
  • spark–sql项目实验
  • 声学重构+交互创新,特伦斯便携钢琴V30Pro专业演奏的移动化时代
  • 信息收集之hack用的网络空间搜索引擎
  • 文件有几十个T,需要做rag,用ragFlow能否快速落地呢?
  • PCB原理图解析(炸鸡派为例)
  • Google独立站和阿里国际站不是一回事
  • Python爬虫与代理IP:高效抓取数据的实战指南
  • Web开发:ABP框架10——使用数据库存储文件,完成文件的下载和上传
  • 【第四章】19-匹配规则定义
  • GPT-4.1 开启智能时代新纪元
  • 算法之动态规划
  • 第42讲:走进智慧农业的“感知神经系统”——农田遥感 + 边缘计算的融合实践