为什么 \newcount 被声明为 \outer?

为什么 \newcount 被声明为 \outer?

我主要使用 Plain TeX。最近我对\outer的性质感到恼火\newcount,尤其是当我编写需要临时内部变量的宏时,这些变量实际上不需要是全局变量。我知道我可以\count0从技术上\count9将 用作临时变量,但当我TeXbook提到它们也被用作页面计数器,以及当触发页面发运时使用它们会弄乱页码。

所以,我的问题是:为什么\newcount声明为\outer?我已经检查过,使用 创建的名称\countdef确实可以在组内本地作用域,并且我知道对\count寄存器的更改同样是本地作用域。那么为什么 Knuth 选择\newcount使用\outer限制进行标记?是否有任何东西阻止我定义自己的\countdef基于 的分配器,特别是允许使用组本地名称的分配器。

答案1

从技术层面上讲,制作宏\outer并不意味着添加\def任何东西:它纯粹是一个限制(与 的子集非常相似\long\def)。因此,这里的推理是为了确保输入遵循特定的模式。

寄存器分配在 plain、LaTeX 和 ConTeXt 中(至少从根本上讲)的实现方式大致相同,但只有 plain 会使用\outer宏来实现。因此,从技术意义上讲,这里使用“普通”宏并不存在“限制”。但使用宏确实\outer可以防止类似

\def\foo#1{%
  \newcount\mycount
   ...
}

您偶尔会认为这是对 TeX 任务范围的误解。(我假设这里\foo在文档中使用多次。)

当然,您仍然可以使用\outer以下方式在其他宏中使用宏\csname

\def\foo#1{%
  \csname newcount\endcsname\mycount
 ...

请注意,LaTeXetex包和“e-plain”格式都包含允许“本地寄存器分配”的代码:etex包代码包含非常小 LaTeX,所以也许可以看看\loccount那个(例如 less `kpsewhich etex.sty`在 *nix 上)。

答案2

计数器非常宝贵,因为它们只有 256 个,而且其中有几个已经被分配或被 TeX 使用:前十个是为页面计数器保留的,这是 DVI 格式的要求;从 10 到 21 的计数器用于与寄存器分配相关的簿记,并\count255作为临时寄存器保存。Plain 格式保留了另外六个(两个通过 隐式保留\newinsert)。
注意:这里我是从使用没有 e-TeX 扩展的原始程序运行的 Plain TeX 的角度出发的。

虽然可用计数器的数量似乎仍然很大,但必须记住,\newcount指令会执行全局分配。让我们看看:

\outer\def\newcount{\alloc@0\count\countdef\insc@unt}
\def\alloc@#1#2#3#4#5{\global\advance\count1#1by\@ne
  \ch@ck#1#4#2% make sure there's still room
  \allocationnumber=\count1#1%
  \global#3#5=\allocationnumber
  \wlog{\string#5=\string#2\the\allocationnumber}}

因此\newcount\foo

\global\advance\count10 by 1
\ch@ck0\ins@count\count
\allocationnumber=\count10
\global\countdef\foo=\allocationnumber
\wlog{\string\foo=\string\count\the\allocationnumber}

我们发现上面的几行

\count10=22 % allocates \count registers 23, 24, ...

所以我们知道\count10存储了最后分配的计数寄存器的编号。用户空间中第一个可用的是编号 23,但 Plain TeX 有三个\newcount指令。因此\newcount\foo将打印

\foo=\count26

在日志文件中。

现在您看到寄存器的分配是连续的。如果不使用池而不是连续策略彻底更改宏,就无法“取消分配”寄存器。

宏定义如下

\def\amacro#1{\newcount\temp \temp=#1\relax ...}

每次调用时都会全局浪费一个寄存器:相信我,我在 LaTeX 宏中见过几次这种错误;正如你所知道的,\newcounter在LaTeX 中\newcount并不存在\outer。有时是\newlength,但想法是一样的。

\newcount通过将和其他类似的分配宏声明为\outer,这种错误(几乎)不可能出现。
请注意,对于 e-TeX 允许的 32768 个寄存器或 LuaTeX 提供的 65536 个寄存器,这也是一个错误。这些寄存器稍后才会耗尽。

在某些情况\newcount下,宏是合法的:如果我们想定义一个接口,比如引入分层分段命令,我们必须允许它\newcount\subsectioncount作为(虚构的)命令的一部分

\definelevel{subsection}{...}

但这里不是“用户空间”: 的定义\definelevel是由程序员做出的,他知道(或至少应该知道)正在做什么。程序员会输入

\csname newcount\expandafter\endcsname\csname#1 count\endcsname

在 的代码中\definelevel,覆盖 的外部性\newcount

相关内容