> For the complete documentation index, see [llms.txt](https://ayakaleaf-pro.ayaka.space/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ayakaleaf-pro.ayaka.space/latex/zh-cn/geng-duo-zhu-ti/20-how-tex-macros-actually-work-part-2.md).

# TeX 宏究竟如何工作：第 2 部分

[第 1 部分](/latex/zh-cn/geng-duo-zhu-ti/19-how-tex-macros-actually-work-part-1.md) [第 2 部分](/latex/zh-cn/geng-duo-zhu-ti/20-how-tex-macros-actually-work-part-2.md) [第 3 部分](/latex/zh-cn/geng-duo-zhu-ti/21-how-tex-macros-actually-work-part-3.md) [第 4 部分](/latex/zh-cn/geng-duo-zhu-ti/22-how-tex-macros-actually-work-part-4.md) [第 5 部分](/latex/zh-cn/geng-duo-zhu-ti/23-how-tex-macros-actually-work-part-5.md) [第 6 部分](/latex/zh-cn/geng-duo-zhu-ti/24-how-tex-macros-actually-work-part-6.md)

## 引言：一则图片故事

如第1部分所述，TeX 必须“读取”你文件中的每一个字符，而这种读取过程更准确地称为 `.tex` 扫描 *扫描*。传统上，TeX 的输入处理（扫描）常被比作 TeX 拥有一双“眼睛”来观察输入，因此我们将在下面的图示中沿用这一经久不衰的类比。

### 图1：眼睛已准备就绪

我们假定 TeX 已经从某个 `.tex` 文件中获取了一些输入，并即将处理我们的字符串 `你好，世界 \jobname` ，它包含在一段文本之中。TeX 会依次检查每个字符，并查看其类别码。

![TeX 的眼睛已准备好扫描一行文本](/files/fcdd7e6f1048de9c4f8bbc5870fcf57530f74ee6)

### 图2：处理类别码

在下一幅图中，我们将以概略方式（更详细内容见下文）看到 TeX 如何对几种不同的类别码作出反应。请注意，总共有 16 种类别码，但为简便起见，我们这里只展示其中三种：11、10 和 0。其他字符码在 TeX 的排版过程中会变得重要，例如构建表格、排版数学公式以及识别宏参数时。

![TeX 对几种不同类别码的反应](/files/c8dd7f916100f648a6750dc11eea422a9b82edf3)

#### 图2说明

在这里，我们考虑的是 TeX 在读取（扫描）构成一段正文的字符时的情况。TeX 会检查每个字符，查看其类别码，并根据类别码以及 TeX 的“模式”（一种基于它当前正在执行什么操作的状态）采取相应行动。

* **（绿色眼睛）** TeX 会看到这些字符中的每一个都具有类别码 11（“字母”），并会将这些字符转发用于排版，作为它正在构建的段落的一部分。然而，TeX 并不会只转发（使用）字符码，而是使用这对数字（字符码，类别码）来计算一个称为 *字符记号* （见下文）。一旦生成了该字符记号，它就会进入 TeX 内部的排版过程/算法。
* **（蓝色眼睛）** TeX 看到一个空格字符（ASCII 32），其类别码为 10（“空白符”）——请注意，正如前面所讨论的，空格（ASCII 32）或任何字符的类别码都很可能在被 TeX 读取之前就已被改成另一个值。

TeX 实际如何处理类别码为 10（“空白符”）的字符，确实会根据 TeX 看到它时所处的位置/时机而有所不同——也就是 TeX 当前的“模式”。例如，有些时候 TeX 会直接跳过它们。在这里，TeX 会知道自己在处理段落文本时检测到了一个类别码为 10 的字符（恰好它是一个空格，ASCII 32），因此最终会把它转换为所谓的词间胶：一种可以伸缩的弹性空白。

* **（红色眼睛）** 这里，TeX 观察到一个具有非常重要类别码的字符：0（转义字符）。

一个转义字符——*任何* 具有类别码 0 的字符——都会告诉 TeX 切换到一种特殊的读取模式，并仔细扫描（读取）后续字符，因为它们标识的是一个 *命令*，而不是要排版的正文。在 TeX 文献中，你会看到术语“command”也被称为 *控制序列*。在看到转义字符后，TeX 会检查其后 *紧跟着的字符*的类别码；这是因为 TeX 识别两种类型的命令：

* 叫作多字母命令 *控制词*：紧接在转义字符之后的字符具有类别码 11。所有后续具有类别码 11 的字符都被视为命令名称的一部分。当 TeX 检测到任何一个 *不会* 不具有类别码 11——例如一个类别码为 10 的空格字符——时，TeX 就会停止寻找构成命令名称的字符。
* 叫作单字母命令 *控制符号*：转义字符后紧跟的字符 *不会* 具有类别码 11。

你可以把转义字符看作是触发 TeX 从通常的扫描行为中“跳出”并对接下来的几个字符采用不同方法的开关——红色虚线框所示表明 TeX 将会 **开始扫描命令**.

### 图3：处理类别码 11（“字母”）

在本系列第1部分中，我们提到 TeX 从输入中读取的每个字符都由两个整数来描述：

* 字符码：定义字符数值表示的整数；
* 类别码：TeX 为可能出现在其输入中的每个字符分配的 0 到 15 之间的值。

TeX 在其处理的下一阶段会使用这两条信息：创建字符记号。

图3是在图2的基础上展开，展示 TeX 对这些类别码为 11（字母）的输入字符所做的事情：它会创建 *字符记号*——TeX 使用该字符的类别码和字符码的组合计算出的整数值。

**注意**：在这个例子中，我们只讨论类别码为 11 的字符，但你应当知道，TeX 也会为其他类别码的输入字符创建记号值——除类别码 0 外，它从不会被转换为记号：转义字符只是充当一个“开关”，用于触发特殊处理。

![TeX 处理类别码为 11 的字符](/files/33bd70977cc0c9845e91f7ef825a3f33986c0f1f)

下面的图5将展示 TeX 在看到类别码为 0 的字符（转义字符）时会做什么。

#### 图3说明：处理类别码 11（“字母”）

这里，我们将重点关注 **green** 活动：当 TeX 看到类别码为 11（“字母”）的字符时会发生什么。在 TeX 读入一个字符并确定其类别码（这里是 11）之后，TeX 下一步要做的是 *将* 这对数字组合成一个称为字符记号的单一整数：这些记号（整数）会被转发到 TeX 内部排版算法/处理的下一阶段。如前所述，TeX 也会为类别码不是 11 的字符创建字符记号，这里我们只是把类别码 11 作为一个示例。

每个字符记号（一个整数）都会把一个输入字符与该字符所分配到的类别码永久绑定 **在它被 TeX 扫描（读入）时**：这一点对于理解 TeX/LaTeX 宏的行为至关重要。当然，在进一步处理过程中，TeX 有时需要拆分一个字符记号，以确定当初构造该记号时使用的是哪一对（字符码，类别码）。不过，一旦字符被 TeX 的输入（扫描）过程读入，TeX 所计算出的字符记号值就会导致该字符被 *永久* 与其被分配的类别码绑定 *在它被读入时*.

**字符记号的计算**

TeX 引擎使用一个简单公式来计算字符记号， $$T$$，由类别码为 $$C$$ 以及字符码为 $$A$$:

$$T = \text{constant} \times C + A$$

8 位引擎，如 pdfTeX，使用：

$$T = 256\times C + A$$

支持 Unicode 的引擎，如 XeTeX 或 LuaTeX，必须使用不同的公式，因为在 Unicode 下，字符码可以远大于旧式 8 位 ASCII 编码世界中的最大值 255。例如，XeTeX 使用：

$$T= 2^{21}\times C + A \hskip5mm \text{(where } A \text{ is a Unicode character code value)}$$

再次强调，值得注意的是，类别码为 0 的字符不会被转换为字符记号：类别码 0 在 TeX 的输入过滤中占有非常特殊的位置，它纯粹被用作一个“开关”，以触发 TeX 进入对接下来几个字符的特殊扫描模式。图5将对此进行说明。

### 图4：处理类别码 10（“空白符”）

TeX 对类别码为 10（“空白符”）的字符的处理，取决于当 TeX 在输入中检测到一个类别码为 10 的字符时它当前正在处理什么。在我们的例子中，TeX 正在进行常规的段落处理，而类别码为 10 的空格字符将被转换为词间胶。

![TeX 处理类别码为 10 的字符](/files/9933ead5eb4ff3f9d8b7649788044e07ca5d2008)

TeX 对空格的处理看起来相当古怪，但在 [《TeX by Topic》](http://www.eijkhout.net/texbytopic/texbytopic.html) 的第1章和第2章中可以找到一个很好的概述——作者是 Victor Eijkhout——你可以 [下载免费的 PDF 版本](https://bitbucket.org/VictorEijkhout/tex-by-topic) 通过他的网站。

例如，当 TeX 看到一个类别码为 10 的字符时，有些时候 TeX 会：

* 跳过（忽略）它们全部——例如，当 TeX 处于垂直模式时；
* 把多个空白符合并成一个空白符——例如在处理段落时会跳过多余空格；
* 吸收它们——例如吸收命令名称后面的一个空格；

另外还要注意，有些时候 TeX 也会 *生成* 空格——通过把行尾字符转换为空格。空格字符（任何类别码为 10 的字符）的行为/处理方式，是 TeX 的“怪癖”之一：要熟悉（并习惯）TeX 的这一方面，需要时间和练习。

### 图5a：处理类别码 0（“转义字符”）

在这幅图中，TeX 已经处理了直到 `\` 字符之前的所有字符，该字符的类别码为 0：即“转义字符”——我们将使用一系列后续图示来展示 TeX 如何处理转义字符并识别命令名称。

![TeX 处理类别码为 0 的字符](/files/372fa6e5ef469e8102576606e1b8916435a144a4)

### 图5b：寻找命令名称

在这幅图中，我们查看红色虚线框部分（**开始扫描命令**）以了解 TeX 在看到转义字符后会做什么。

![TeX 正在寻找命令名称](/files/e4659b28300bfb769e171e68f27dd2d181a7aff6)

**图5b说明**

* 一旦被识别，转义字符就完成了它的工作：它充当了一个开关，并且不再参与任何后续处理——具体来说，它 **不** 被转换为一个字符记号。
* 为方便起见，我们重复一下前面提到的一些细节。在看到转义字符后，TeX 会检查其后 *紧跟着的字符*的类别码；这是因为 TeX 识别两种类型的命令：
* * 叫作多字母命令 *控制词*：紧接在转义字符之后的字符具有类别码 11。所有后续具有类别码 11 的字符都被视为构成一个命令（*控制词*）。TeX 会在检测到任何一个 *不会* 不具有类别码 11——例如一个类别码为 10 的空格字符——时，TeX 就会停止寻找构成命令名称的字符。
  * 叫作单字母命令 *控制符号*：转义字符后紧跟的字符 *不会* 具有类别码 11。
* 在我们的例子中， `\` 是 `j` 之后的第一个字符是
* （类别码 11），这告诉 TeX 要寻找一个（可能是）由类别码 11 的多个字符组成的命令。TeX 会继续检查更多具有类别码 11 的字符。一旦它检测到任何其他类别码的字符，例如一个类别码为 10 的空格，TeX 就知道命令名称已经结束。为了强调这一点：这里是一个空格字符（类别码 10）“终止”了命令的末尾，但它也可能是任何一个 **没有** 具有类别码 11。

## 第 3 部分

在第3部分中，我们将从图5b继续，完成这段故事的这一部分——TeX 如何识别一个命令——并接着看它下一步做什么。我们还会更深入地了解 TeX 处理的一些内部方面——其中一部分在第一次阅读时可以跳过，除非你真的喜欢这些细节。

[第 1 部分](/latex/zh-cn/geng-duo-zhu-ti/19-how-tex-macros-actually-work-part-1.md) [第 2 部分](/latex/zh-cn/geng-duo-zhu-ti/20-how-tex-macros-actually-work-part-2.md) [第 3 部分](/latex/zh-cn/geng-duo-zhu-ti/21-how-tex-macros-actually-work-part-3.md) [第 4 部分](/latex/zh-cn/geng-duo-zhu-ti/22-how-tex-macros-actually-work-part-4.md) [第 5 部分](/latex/zh-cn/geng-duo-zhu-ti/23-how-tex-macros-actually-work-part-5.md) [第 6 部分](/latex/zh-cn/geng-duo-zhu-ti/24-how-tex-macros-actually-work-part-6.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://ayakaleaf-pro.ayaka.space/latex/zh-cn/geng-duo-zhu-ti/20-how-tex-macros-actually-work-part-2.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
