我正在创建包含各种参考、引文、索引、目录和其他链接元素的文档。LaTeX 如何知道如何正确地交叉引用页面,同时正确地格式化页面并保持页码正确?
Latex 如何知道插入页面引用不会修改所引用标签的页面?
例如,如果我在文档后面引用了某个部分,\ref{sec:bestsection}
那么 LaTeX 必须稍后找出该部分\label{sec:bestsction}
位于哪个页面,然后返回并将其插入到\ref
第二次编译的位置(请参阅这个答案)。
但是,假设我有一个很大的文档,并且恰好sec:bestsection
在第10230。另外,假设这个大页码恰好为文档增加了足够的空间,以至于将另一个单词推到了页面末尾。一件事导致另一件事,现在sec:bestsection
在第10231。
LaTeX 如何知道发生了这种情况并且不使用错误的页码?它是否总是假设 a\ref
适合该行?
答案1
标题中问题的答案是“LaTeX没有知道”,至少不是完全知道。
LaTeX 如何管理交叉引用?
假设你有
As we shall see in section~\ref{sec!main-results}, ...
...[many pages later]...
\section{Main results}\label{sec!main-results}
We are now ready to prove the most important theorems.
看到的时候\label
,页面\ref
早已排版输出了:根本没办法“找回来修号”。
因此,这种方法不是“一次性正确获取所有交叉引用”,因为它需要在进行任何排版之前将整个文档保存在内存中。相反,LaTeX 在输出\label
出现命令的页面时会立即写一条注释:在.aux
文件中,你会发现类似
\newlabel{sec!main-results}{{3}{9}}
其中第一个数字是章节号,第二个数字是页码。只有在发送页面时才会写出注释,因为只有这样才能真正知道页码。请记住,TeX 总是会提前查看,并且只排版完整段落,然后再决定分页符。
在作业结束时,.aux
文件被关闭并输入。此时\newlabel
会获得一个适当的定义,其目的是检查标签是否在之前的运行中已知,在这种情况下,其中一个相关数字是否已更改。
此时你会看到如下警告
Label(s) may have changed. Rerun to get cross-references right
There were multiply-defined labels
Label `<label>' multiply defined
这应该是不言自明的。
在作业开始时,当 LaTeX 正在处理时\begin{document}
,.aux
文件被输入并\newlabel
获得不同的定义,这允许\ref{sec!main-results}
或\pageref{sec!main-results}
打印正确的数字。但是什么数字?在上述情况下,即使您在运行之间添加了整个部分,部分编号也将是 3。只有在作业结束时,LaTeX 才会知道数字已更改,并且它会发出上面列出的第一个警告。
如果交叉引用未知,则??
只会打印并发出有关已更改标签的警告。如果\ref
或\pageref
命令引用尚未定义的标签,则会收到警告
There were undefined references
但是也
Reference `<label>' on page <page> undefined
它会告诉你,也许你拼错了标签。
我们应该关心交叉引用的大小吗?
我们应该关心参考文献使用的空间吗?其实不必。段落通常具有足够的灵活性,允许收缩或拉伸一行而不会对输出进行实质性修改。这并非万无一失,而且有一些巧妙编写的文档永远无法稳定的例子:每次运行 LaTeX 都会更改与标签关联的页码,因此它永远不会保持不变。但是,这种情况在真实文档中发生的几率非常小。
那么多次运行怎么样?
文档处理器(例如)latexmk
能够查看.log
文件中有关已更改标签或未定义引用的警告,并触发新运行以修复输出。但是,交叉引用在每个时间点是否正确并不那么重要:当您没有收到上述警告时,它们就是正确的。
那文件怎么办.aux
?
该.aux
文件还有其他几个用途:例如引用,但也用于其他管理任务。软件包(尤其是hyperref
)可以通过扩展两个版本的语法来修改所做的注释\newlabel
,但处理这个问题会太耗时。想法仍然是一样的。
.aux
重要提示。从这个描述中可以清楚地看出,在运行之间保持文件的完整性是基本的。除非由于某些致命错误而损坏,否则通常不应删除此文件。不完整的注释可能会导致输入文件时出错:在此错误处中断 LaTeX 运行将保留相同的损坏文件,因此在下次运行时将再次出现相同的错误。在这种情况下,删除文件.aux
是唯一的补救措施。没什么大不了的,它将花费一次新的 LaTeX 运行(可能两次)。但是,当然,.aux
在运行结束时删除正确的文件将总是产生有关未定义引用的错误。
最后,有一个开关可以让 LaTeX 不触及它写出的任何文件:如果你\nofiles
在序言中添加,则.aux
文件和用于目录和类似列表的文件将仅被输入而不会被重写。这是过去的遗留问题,当时即使写入文件或只是保持某些文件打开也会导致延迟,因此当人们确定交叉引用和列表是正确的时候,添加\nofiles
可以节省一些运行时间。如今,开销非常小,以至于这种技巧几乎毫无用处。
答案2
它将所有引用的页码写入辅助文件。请注意,在第一次运行时,如果没有辅助文件,它会改为输入 ??。在以后的运行中,它会首先读取辅助文件。然后,当它记录页码时,它会将页码与上次运行中写入辅助文件的页码进行比较。如果任何引用不同,它会在运行结束时发出警告。
但可以想象,这个过程永远不会结束。随着页码位数的增加,可以想象(勉强)段落将变成一行更短,这是由于段落构建算法的工作方式。这反过来又会将引用的页面向后移动一页,从而再次缩短页码。但我认为你必须非常努力才能想出一个例子。
如果您使用罗马数字来编号页面,则会更容易一些:现在后面的页码可以使用更短的数字,这更有可能将段落缩短一行。
答案3
这就是为什么你需要运行 latex 两到三次(或更多次)的原因,如果你运行 latexmyfile.tex
然后查看myfile.aux
,你会看到所有的交叉引用信息。因此,在第一次运行时,引用是公正的,?
但之后它使用上次写出的值。在运行结束时,latex 会进行一致性检查,以确保它写入的值与读入的值相同,如果它们不同,它会发出“标签已更改,重新运行 LaTeX”警告。