本文由 AI 辅助生成并经自动审查;尚未完成真实硬件验证。涉及具体芯片、时序和电气行为时,请以文末第一方资料和实际测试为准。
第 2 课:第一个 C 程序:按顺序得到确定结果 #
本课只建立一个核心概念:最小 C 程序按语句顺序执行,并得到确定结果。我们先在普通 Windows 主机上验证逻辑;没有开发板、目标工程或运行记录,因此这不是硬件验证。
1. 本节目标 #
完成本课后,你应该能在主机上阅读并修改一个单文件 C11 子集程序,说明它怎样按语句顺序完成一次确定计算,并通过程序的退出状态观察结果;同时能说明主机结果不能证明程序已经在嵌入式目标上运行。
预计用时 30 分钟。
2. 它解决什么问题 #
第一次看到 C 代码时,很容易只盯着符号,却不知道运行时先发生什么、后发生什么。本课把问题缩小到三个可观察的问题:
- 程序从哪里开始执行本课代码?
- 每条语句怎样改变当前结果?
- 程序结束后,怎样在不依赖硬件的情况下看到结果?
当前没有具体开发板,所以实验不能依赖引脚、时钟、外设或调试器。我们用主机的退出状态承载一个小范围结果,只验证顺序计算逻辑。
3. 必要前置知识 #
已完成的上一课提供两个结论:
- 主机与嵌入式目标的运行环境不同;
源文件 -> 构建产物 -> 运行 -> 可观察结果才是最小验证闭环。
本课不假定你已经学过 C 语法。你只需要一台 Windows 主机、PowerShell,以及能在终端调用的 GCC C 编译器。先运行:
gcc --version若系统提示找不到 gcc,说明实验依赖尚未满足,应先配置编译器;这不能用来判断示例代码是否正确。
4. 核心原理 #
最小程序不是“一次同时做完所有事情”,而是从 main 中第一条语句开始,一条接一条执行。前一条完整表达式产生的结果会在程序进入后续代码前生效;赋值会先计算右侧,再把结果保存到左侧指定的位置。[1]
- 解决什么问题:让我们能预测程序每一步以及最终结果,而不是凭运行后的数字猜测。
- 对象在哪里定义:要执行的语句和初始值都写在
main.c的main中。 - 谁持有它:源文件保存文字规则;程序运行时,当前的
result值由这个正在运行的主机程序持有。 - 谁注入它:本例没有外部输入;学习者把初始值
4直接写入源文件,主机负责启动构建产物。 - 调用如何流动:主机启动
lesson.exe,执行进入main,语句依次把result从4变为7,main返回7,PowerShell 再读取退出状态。
这里的“依次”是本课重点。若交换会依赖前一步结果的语句,最终结果可能改变;若源文件和输入不变,这个简单计算的预期结果也不变。
5. 关键术语与直观模型 #
| 术语 | 本课中的准确含义 |
|---|---|
| 源文件 | 保存 C 程序文本的文件,本课名为 main.c。 |
main |
此最小主机程序开始执行本课代码时使用的函数名称;目标启动过程以后再学。 |
| 语句 | 让程序完成一个小动作的 C 代码单元,通常以分号结束。 |
| 返回值 | main 结束时交给主机的整数结果。 |
| 构建产物 | 根据源文件生成、可由当前主机运行的程序文件,本课名为 lesson.exe。 |
| 退出状态 | 程序结束后由主机保存、可被 PowerShell 读取的数值。 |
| Host Fake(主机替身) | 没有目标硬件时,在主机上替代硬件依赖以验证逻辑的方法。 |
把 result 想成纸上的一个格子:第一条语句写入 4,第二条语句取出旧值、加 3,再把 7 写回同一个格子。result 是变量,也就是运行时可保存一个值的命名位置。
6. 从输入到结果的完整流程 #
- 学习者把程序文字保存为
main.c。 - GCC 读取源文件,生成主机构建产物
lesson.exe。本课只使用这个整体能力,不展开内部处理阶段。[2] - PowerShell 请求 Windows 启动
lesson.exe。 - 程序进入
main,先执行int result = 4;,此时result为4。 - 接着执行
result = result + 3;,先使用旧值4计算,再保存新值7。 - 最后执行
return result;,main返回7,进程结束,并把这个小范围值作为退出状态报告给父进程。[1] - PowerShell 中的
$LASTEXITCODE显示最近一次本机程序的退出状态,预期为7。
本实验特意不打印文本:这样可以集中观察“计算结果 -> 返回值 -> 退出状态”这一条路径。
7. 嵌入式系统中的对应位置 #
源文件中的顺序计算可以迁移到嵌入式程序,但运行边界不同。STM32 官方开发工具文档把工程构建、运行与调试放在面向目标设备的开发流程中;主机上的 .exe 不能代替目标构建产物或下载、调试证据。[3]
以后有具体开发板时,可以在目标工程的适当位置执行同样的纯计算,并用调试器观察变量。但从处理器启动到进入目标程序 main 的过程不等同于 Windows 启动 .exe,本课不展开,也不猜测具体芯片配置。
8. 主机实验与硬件迁移边界 #
本例没有 GPIO 等硬件依赖,因此只是主机逻辑验证,没有引入实际的 Host Fake。以后代码依赖 GPIO、传感器等硬件接口时,才需要用可控的主机对象替代那些依赖。当前实验只能证明:为当前主机构建并实际运行的程序,按预期顺序得到退出状态 7。
它不能证明:
- 代码已经为 STM32 构建;
- 固件已经下载到开发板;
- 任一引脚、时钟或外设工作正常;
- F4、F7、H5 或 H7 上存在相同的启动和观察方式。
硬件迁移时应另外保存目标构建、下载和调试观察证据。当前 hardware_verified=false。
9. 最小代码示例 #
将以下内容保存为 main.c:
int main(void)
{
int result = 4;
result = result + 3;
return result;
}这是单文件 C11 子集示例,不使用动态内存。代码属于主机逻辑验证层,依赖方向只有“主机启动程序并接收返回值”。本课不讨论 int 的宽度、表示范围或溢出,这些属于下一主题 integer-model。
状态说明:示例,待主机验证;若迁移到硬件,仍待上板验证。
10. 常见错误 #
- 从下往上读代码:运行顺序是进入
main后从第一条语句向后推进。 - 把第二行算成
3:右侧result使用前一步保存的4,所以新值是7。 - 修改源文件后直接运行旧程序:旧的
lesson.exe不会自动包含新文字,必须重新构建。 - 只运行
$LASTEXITCODE:它表示最近一次本机程序的状态,应紧接着运行lesson.exe后读取。 - 把
7当成硬件证据:它只来自 Windows 主机进程。
11. 调试观察点 #
按流程定位问题:
gcc --version是否能显示编译器信息。- 当前目录是否存在刚保存的
main.c。 - 构建命令是否报告错误,目录中是否出现新的
lesson.exe。 - 执行
lesson.exe后是否立即读取$LASTEXITCODE。 - 若结果不是
7,核对初始值、加数和是否在修改后重新构建。
有主机调试器时,可选地逐语句执行并观察 result 依次为 4、7;本课不要求安装或使用特定调试器。
12. 实战实验 #
在含有 main.c 的目录打开 PowerShell,逐条执行:
gcc -std=c11 -Wall -Wextra -pedantic main.c -o lesson.exe
.\lesson.exe
$LASTEXITCODE预期最后一条命令显示:
7然后只把初始值改成 5,先在纸上预测结果,再重新构建和运行。预期退出状态为 8。最后把加数改成 4,再次先预测、后验证,预期为 9。
在真实运行记录产生前,以上结果都是预期值,不能声称已经编译或运行成功。实验完成后应保留命令、编译器版本、实际输出和时间,才能形成主机验证证据。
13. 自检题 #
result为什么在第二条语句之后是7?return result;之后,哪个主机机制让结果可观察?- 修改
main.c后为什么要重新构建? - 如果初始值为
6、加数为2,退出状态应是多少? - 为什么主机上看到预期结果仍不能设置
hardware_verified=true?
14. 面试题 #
问:如何解释这个最小 C 程序从启动到结果可见的完整流动?
答题要点:Windows 启动主机构建产物;执行进入 main;语句按书写顺序更新局部变量;main 返回小范围整数;主机保存退出状态;PowerShell 读取该状态。还应主动说明,这不是 Cortex-M 启动调用链或上板证据。
15. 延伸思考 #
- 若把“加
3”放到“写入初始值4”之前,程序还具备当前相同的清晰含义吗?为什么? - 如果程序中有两次连续加法,怎样在纸上记录每条语句之后的值?
- 未来有硬件后,除了退出状态,还能通过哪些通用手段观察计算结果?只列类别,不假定具体外设。
16. 本节总结 #
最小 C 程序从 main 中的第一条语句开始,按顺序完成小动作。前一步保存的值可以成为后一步的输入,最后由 main 的返回值进入主机退出状态。本课用 4 -> 7 -> 退出状态 7 建立了可手工预测、可主机观察的最小逻辑闭环。
17. 下一步 #
下一课应由课程规划决定是否进入 integer-model,系统学习整数的宽度、范围与表示规则。本课生成本身不代表已经掌握;只有自检答案、实验记录或复习结果才能提高掌握度。
18. 参考资料 #
- GNU Project, GNU C Language Introduction and Reference Manual, version 0.1, 5 May 2025,访问日期:2026-09-21。核对位置:
Simple Assignment、Sequence Points、Returning Values from main;用于支撑赋值、完整表达式之间的执行顺序以及main返回值成为退出状态。 - GNU Project, Using the GNU Compiler Collection (GCC): Invoking GCC, GCC 14.2.0,访问日期:2026-09-21。用于核对 GCC 调用方式与从输入文件生成程序的整体表述。
- STMicroelectronics, STM32CubeIDE user guide, UM2609 Rev 18, June 2026,访问日期:2026-09-21。用于核对 STM32 目标工程的构建、运行与调试背景,以及主机验证与目标工作流的边界。