在内核中 的定义包括到
protected@write
的设置。为什么会这样?还有其他方法可以确保不扩展吗?\thepage
\relax
thepage
\long\def \protected@write#1#2#3{%
\begingroup
\let\thepage\relax
#2%
\let\protect\@unexpandable@protect
\edef\reserved@a{\write#1{#3}}%
\reserved@a
\endgroup
\if@nobreak\ifvmode\nobreak\fi\fi
}
答案1
这是一个很棒的技巧不是吗:-)
直到页面在输出例程中输出后才会\write
发生(事实并非如此\immediate
),因此您需要对\edef
大多数宏进行扩展,以便它们在您知道它们已定义时进行扩展,否则本地环境可能会结束,参数中的所有宏都变为未定义,并且在期间您会收到未定义的命令错误\shipout
。但使用延迟写入的主要原因是,交叉引用等的页码会以正确的数字写出,而正确的数字只有在时才为人所知,因此\shipout
您不希望它过早扩展。因此,首先执行\edef
设置\thepage
为的设置\relax
,这样它就不会扩展,然后\write
该结果\thepage
可以在输出例程的稍后部分进行扩展。
答案2
如果在期间扩大\edef\reserved@a
,它可以有错误的页码。相反,它以未展开的形式传递到 中\write
,这将在下一次 shipout 操作期间执行,在那里它将扩展为正确的值。那时对 的重新定义\relax
将被遗忘。
当控制序列等效于操作\relax
中其保持不变时\edef
(对于任何不可扩展的标记也是如此)。