2026.10.27 笔记

Tips1

全局变量和静态变量的生命周期完全相同,都是"整个程序运行期间" ;它们的真正区别在于作用域(可见范围),而不是存活时间。

生命周期对比

类型 生命周期 说明
普通全局变量 程序开始 → 程序结束 程序启动时创建,结束时销毁
静态全局变量 程序开始 → 程序结束 生命周期与普通全局变量完全一样
静态局部变量 程序开始 → 程序结束 第一次进入函数时初始化,之后一直保持

三者都存放在RAM静态存储区 (.data 或 .bss 段),不会像局部变量那样在函数返回时被释放。

真正区别在"作用域"

  • 普通全局变量 :整个程序可见,其他 .c 文件可以用 extern 访问。
  • 静态全局变量 :只在定义它的那个 .c 文件内可见,其他文件无法访问。
  • 静态局部变量:只在定义它的函数内可见,但函数返回后值不会丢失,下次调用仍保留上次的值。

一句话记

static 放在全局变量前,是"缩小可见范围";放在局部变量前,是"延长存活时间"。 但无论哪种静态变量,生命周期都和全局变量一样,贯穿整个程序运行期。


Tips2

const 在 C 语言里不是"常量定义器",而是只读限定符:它告诉编译器,这个对象不能通过这个标识符被修改。

1. 修饰普通变量

c 复制代码
const int a = 10;
int const b = 20;   // 和上面等价
  • 必须在定义时初始化。
  • 之后不能赋值、不能 a++。
  • 在 C 语言里,const int a 仍是只读变量 ,不能当编译期常量用,比如不能写成 int arr[a];。

2. 修饰指针:看 const 在 * 的哪一侧

写法 含义 能否改
const int *p / int const *p 指向常量的指针 不能改 *p,可以改 p
int * const p 常量指针 不能改 p,可以改 *p
const int * const p 指向常量的常量指针 p 和 *p 都不能改

记忆方法:const 靠近谁,谁就不可改。

c 复制代码
int x = 10, y = 20;

const int *p1 = &x;   // 不能 *p1 = 30;可以 p1 = &y
int * const p2 = &x;  // 可以 *p2 = 30;不能 p2 = &y
const int * const p3 = &x; // 都不能改

3. 修饰数组

c 复制代码
const int arr[3] = {1, 2, 3};
arr[0] = 10;   // 错误:元素只读

函数参数里也常用:

c 复制代码
void printArray(const int arr[], int size) {
    // arr[i] = 0;  // 错误:保护数组内容不被修改
}

这里 const int arr[] 本质上等价于 const int *arr。

4. 修饰函数参数和返回值

修饰参数,主要是保护传入的数据:

c 复制代码
void printStr(const char *str) {
    // *str = 'A';  // 错误:不能修改传入字符串内容
}

修饰返回值,通常用于返回指针时,防止调用者直接修改:

c 复制代码
const char *getName(void);

5. 嵌入式里两个容易踩的点

  • const 全局数组、表、字库等,常被放在 Flash/ROM 里,不占 RAM。
  • 如果是硬件寄存器,只读但可能被硬件改变,通常写成:
c 复制代码
volatile const uint32_t *reg = (volatile const uint32_t *)0x40000000;

const 表示程序不该写它,volatile 表示值可能被外部改变。

一句话记

const 修饰的是"通过这个名字不能改",不是"物理上永远不能改"。 指针场景里,只要抓住"const 靠近谁,谁只读",基本就不会乱。

Tips3

可以按"编译器段名 / 加载视图 / 运行视图 / 堆栈"四层来理解,这样不容易混。

1. 先分清两套叫法

编译器输出 对应段名 含义
Code .text 程序指令
RO-data .rodata 只读数据,如 const 全局量、字符串常量
RW-data .data 已初始化且初值非 0 的全局/静态变量
ZI-data .bss 未初始化或初始化为 0 的全局/静态变量
Stack --- 局部变量、函数参数、返回地址
Heap --- malloc 动态分配

前四个是编译后静态段 ,Stack 和 Heap 是运行时的 RAM 区域。

2. 加载时:程序存在 Flash/ROM 里的样子

程序还没运行、只是烧进 Flash 时:

text 复制代码
Flash/ROM = Code + RO-data + RW-data
  • Code:机器指令。
  • RO-data:只读数据,运行后也不复制到 RAM。
  • RW-data 的初始值:必须存在 Flash 里,否则掉电后初值就丢了。
  • ZI-data 不占 Flash:因为它的初值就是 0,上电后清零即可,没必要在 Flash 里存一份。

3. 运行时:程序在 RAM 里的样子

上电后,启动代码会做两件事:

  1. 把 RW-data 的初始值从 Flash 复制到 RAM;
  2. 把 ZI-data 区域全部清零。

所以运行时的 RAM 占用是:

text 复制代码
RAM = RW-data + ZI-data + Stack + Heap

其中编译器统计的:

text 复制代码
RW Size = RW-data + ZI-data

表示静态变量占用的 RAM;而 Stack 和 Heap 通常也归在 ZI-data 区域统计里,但它们的大小是启动文件里预留的,真正使用多少要运行时才知道。

4. 每个段对应哪些 C 语言对象

段 存放内容 是否掉电保存
Code 函数代码、指令 是,Flash
RO-data const 全局/静态变量、字符串常量 是,Flash
RW-data int g = 10; 这类非 0 初值全局/静态变量 初值在 Flash,运行在 RAM
ZI-data / .bss int g;、int g = 0; 这类全局/静态变量 否,运行在 RAM
Stack 局部变量、函数参数、返回地址 否
Heap malloc 分配出来的内存 否

5. 一句话记

Code 和 RO-data 常驻 Flash;RW-data 的初值存在 Flash,运行时搬到 RAM;ZI-data 只占 RAM,上电清零;Stack 和 Heap 是运行时在 RAM 里动态使用的区域,通常也归入 ZI-data 统计。

在单片机里,如果看到编译输出里 RW-data 很大,通常说明全局/静态变量初值表占得多;如果 ZI-data 很大,通常是未初始化/零初始化全局变量、数组、栈或堆预留比较多。


相关推荐
小陈phd1 小时前
深入理解agent学习笔记(十一)——用户记忆系统
笔记·学习
无心水1 小时前
8、系统架构设计基础知识 核心考点与学习笔记
笔记·学习·系统架构·架构师·软考·软考架构师·软考高级架构师
Li_RuiQi15 小时前
DAgger方法演进_独立学习笔记
笔记·学习·计算机视觉
Li_RuiQi20 小时前
DAgger与交互式模仿学习_ACT学习笔记
笔记·学习
He BianGu20 小时前
【笔记】C# 中BindingFlags的详细作用
笔记·c#
AI视觉网奇20 小时前
turtle 入门教程笔记
笔记
跨知易知识产权21 小时前
美国专利确权是什么,和专利诉讼有什么不一样?
笔记
杨逢昌工厂6S管理21 小时前
126-杨逢昌6S三环体系:越做越乱的现场熵增机理与基准化治理——一线现场诊断笔记
经验分享·笔记·职场和发展·学习方法
悟道书生21 小时前
若依 RBAC 权限控制学习笔记
java·网络·笔记·sql·学习·vue