从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)。

    生命周期:整个程序运行期间。

    作用域:

    修饰全局变量:仅在当前文件内可见(限制作用域)。

    修饰局部变量:仅在函数内可见,但生命周期延长到程序结束。

    示例:

    c 复制代码
    static int x;          // 未初始化,存储在.bss
    static int y = 10;     // 已初始化,存储在.data
    
    void func() {
        static int count = 0; // 存储在.data,函数调用间保持值
        count++;
    }
  • volatile 修饰的变量

    存储位置:由变量定义的位置决定(如全局volatile在数据段,局部volatile在栈)。

    作用:告诉编译器不要优化 对该变量的访问(每次从内存读取,防止缓存优化 )。

    典型用途:硬件寄存器、多线程共享变量

    示例:

    c 复制代码
    volatile int *hw_reg = (volatile int*)0xFFFF0000; // 硬件寄存器地址
    volatile int flag = 0;
    while (flag == 0) {
        // 编译器不会优化为 if (flag == 0) while (true);
        // 每次循环都会从内存读取flag的值
    }
  • auto (默认修饰符)

    存储位置:栈(Stack)。

    生命周期:函数调用时创建,返回时释放

    示例:

    c 复制代码
    void func() {
        auto int x = 5; // 等同于 int x = 5;
    }
  • register (建议性修饰符)

    存储位置:尝试 将变量存储在CPU寄存器(非内存),但由编译器决定。

    限制:不能 取地址(**&**操作)。

    示例:

    c 复制代码
    register int i; // 建议编译器将i放入寄存器
    ;
    int* get_local_ptr() {
        int x = 10; // x在栈上
        return &x;  // 错误!函数返回后x的内存失效
    }
  • extern

    存储位置:声明外部已定义的变量(实际存储位置由定义决定)。

    作用:跨文件引用全局变量。

    示例:

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

    c 复制代码
    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)。

    示例:

    c 复制代码
    int *arr = (int*)malloc(10 * sizeof(int)); // arr在栈,指向堆内存

1.4 典型问题

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

1.5 总结

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

DDR内存(运行时)
   ├── 代码段(只读)
   ├── 数据段
   ├── 堆(动态分配)
   └── 栈(自动管理)
相关推荐
zhangjipinggom几秒前
怎么安装python3.5-以及怎么在这个环境下安装包
开发语言·python
格子先生Lab3 分钟前
Java反射机制深度解析与应用案例
java·开发语言·python·反射
海洋与大气科学35 分钟前
【matlab】地图上的小图
开发语言·数据库·matlab
wenchm1 小时前
细说STM32单片机FreeRTOS任务管理API函数vTaskList()的使用方法
c语言·c++·stm32·单片机·嵌入式硬件
Java知识库1 小时前
Java BIO、NIO、AIO、Netty面试题(已整理全套PDF版本)
java·开发语言·jvm·面试·程序员
techdashen1 小时前
性能比拼: Rust vs Zig vs Go
开发语言·golang·rust
爱编程的鱼1 小时前
C# 封装教程
开发语言·c#
0wioiw01 小时前
Kotlin基础(①)
android·开发语言·kotlin
西瓜本瓜@1 小时前
在 Android 中实现通话录音
android·java·开发语言·学习·github·android-studio
患得患失9492 小时前
【后端】【python】Python 爬虫常用的框架解析
开发语言·爬虫·python