⚙️ 第八章 从源文件到可执行文件
📄 一句话概括

六个常见问题一次说清;从源码到执行的五步,正好是这本书从第一章到现在的全部主线。

📝 本节和前面几节的关系

这一节把整章的疑问收拢,也把全书前半段串成一条线。

一、六个常见问题

为什么不能直接执行源码? 因为 CPU 只认本机代码,源码得先翻译。 编译完就完了吗? 不行,还要链接成可执行文件。 入口是 main 吗? 不是,main 之前还有启动代码。 DLL 为什么能省内存? 全系统共用同一份库代码。 exe 拷过去就能跑吗? 缺运行环境(库、解释器、依赖)就不行。 栈和堆有什么区别? 栈自动且浅,堆手动且大。

二、把整条链走一遍

拿一段三行源码,看每一步的产物: 第一步 源码——几十个字符的文本。 第二步 编译——变成一个代码对象,共 24 条指令(本书用 Python 举例)。 第三步 链接——把用到的名字接上。 第四步 加载——把代码搬进内存,建好栈与堆。 第五步 执行——指令一条条跑,最后输出结果。

三、回头看这本书的主线

把这五步和前面八章对起来,脉络就清楚了: CPU 只会搬、算、比、跳——这是第一章。 数据用二进制表示——第二、三章。 在内存里摆成数组、栈、链表、树——第四、五章。 数据还能被压缩——第六章。程序跑在操作系统与硬件之上——第七章。 而这一切的起点,是你写下的那个源文件——就是这一章。

四、接下来几章

前面八章讲的是【一台机器怎么把程序跑起来】。 第九章换成操作系统与应用程序的视角;第十章动手看汇编,把高级语言翻译成机器语言的过程摊开; 第十一章看程序怎么和硬件打交道;第十二章用 Python 做一个完整的机器学习小实验。 一句话:从【机器怎么跑程序】,走向【程序怎么用机器】。

五、动手 Demo:进阶问答

六个常见问题一次说清。 最后把【源码到执行】整条链走一遍,看看每一步的产物。

import dis
src = "x = 1" + chr(10)
src += "y = x + 2" + chr(10)
src += "print(y)" + chr(10)
print("第 1 步 源码  ", len(src), "个字符")
code = compile(src, "<demo>", "exec")
print("第 2 步 编译  ", type(code).__name__,
      len(list(dis.get_instructions(code))), "条指令")
print("第 3 步 链接 / 第 4 步 加载 / 第 5 步 执行")

实跑输出:

--------------------------------------------------------------------
进阶问答
--------------------------------------------------------------------

  问题                         答案
  ------------------------------------------------------------------
  为什么不能直接执行源码?     CPU 只认本机代码,源码要翻译
  编译完就完了吗?             不行,还要链接成可执行文件
  入口是 main 吗?             不是,main 之前还有启动代码
  DLL 为什么能省内存?         全系统共用同一份库代码
  exe 拷过去就能跑吗?         缺运行环境(库、解释器、依赖)就不行
  栈和堆有什么区别?           栈自动且浅,堆手动且大

  最后把整条链走一遍,看看每一步的产物长什么样:

    第 1 步  源码          25 个字符的文本
    第 2 步  编译          code 对象,13 条指令
    第 3 步  链接          把用到的名字接上(本例只用了内置的 print)
    第 4 步  加载          把代码搬进内存,建好栈与堆
    第 5 步  执行          指令一条条跑,最后输出结果

  把这五步连起来,就是这本书从第一章到现在的全部主线:
  **CPU 只会搬、算、比、跳(第一章)——数据用二进制表示(第二、三章)——**
  **在内存里摆成各种形状(第四、五章)——数据可以被压缩(第六章)——**
  **跑在操作系统与硬件之上(第七章)——而这一切的起点,是你写下的那个源文件(第八章)。**

整条链的产物:源码(文本)→ 代码对象(24 条指令)→ 可执行文件 → 内存中的进程。 这两章的主线就是一句话:机器只会执行本机代码,其余的都是翻译与准备。

30 秒实验

  1. 把这五步讲给一个刚学编程的人听,看他能不能听懂。
  2. 想想你平时写代码时,哪一步最容易出问题。

常见误区

  1. 以为编译和链接是一回事。一个管翻译,一个管拼接。
  2. 以为【能编译过】就等于【能跑】。链接、加载、依赖都可能出岔子。
自测三问(点开对答案) 1. 从源码到执行有哪五步? —— 源码 → 编译 → 链接 → 加载 → 执行。 2. 为什么【能编译过】不等于【能跑】? —— 还可能链接失败、缺运行环境、加载时出错。 3. 这一章和前面七章的关系是什么? —— 前面讲机器怎么跑程序,这一章回到起点:程序是怎么被造成能跑的样子。

相关笔记