了解引用和标签的工作原理

了解引用和标签的工作原理

我试图理解为什么我不能有效地引用我用标签定义的图形或方程式。

例如:

\begin{figure}
  \label{fig:area_Treasuries}
  \caption{Treasuries as a portion of total financial flows.}
  \centering
  \includegraphics[width=0.75\textwidth]{graphs/Area_Treasuries.png}
\end{figure}

\paragraph{}
Figure~\ref{fig:area_Treasuries} presents Treasuries (both flowing
into and out of the United States) as a share of total financial
flows.  From 1985 to 2010, Treasuries account for, on average, 53.2\%
of total financial flows.

使用上述代码,我收到此警告:

LaTeX 警告:参考第 37 页上的“fig:area_Treasuries”在输入行 477 上未定义。

结果是“图?? 代表国库券...”

为什么会发生这种情况?相关,我不明白为什么我不能引用实际方程式之前(我的意思是在文本中物理上高于实际方程式)的方程式。难道这不是多次编译和交叉引用应该解决的问题吗?

答案1

\label考虑使用-系统时,需要考虑很多事情\ref。对于许多人来说,这是自然而然的事情,但一旦你理解了它,它应该可以帮助解决你的大多数问题。


1. 放置\label

是的,这很重要。为什么?嗯,\labelLaTeX 内核作为

\def\label#1{\@bsphack
  \protected@write\@auxout{}%
         {\string\newlabel{#1}{{\@currentlabel}{\thepage}}}%
  \@esphack}

请注意(尽管发生了其他事情),它还是会向文件中写入.aux如下内容:

\newlabel{<label>}{{<currentlabel>}{<page>}}

其中<label>是表单中的供给\label{<label>}<currentlabel>是 的当前值\@currentlabel- 一个宏,通常在您调用 时更新\refstepcounter{<cntr>}。因此,如果\@currentlabel不是根据您所追求的引用而更新的,那么您将获得错误的引用。最值得注意的是,当您放置一个\label \caption,因为\caption增加了一些计数器(figuretable计数器,说)。是文档中出现引用的页面,并且当时<page>具有的值——这可以是定义中规定的任何内容,只是为了清楚起见。\thepage\thepage

底线:由于\label用途\@currentlabel,请确保您的放置位置\label对其进行更新。在某些情况下,您可以避免这种情况,因为计数器更新发生在环境的开始处(通常在定理中),或者环境以这样一种方式编写,即通过\label多次传递捕获并正确分配给计数器,或者只是常规收集过程。

有些人试图\label通过放置来避免这种放置混乱\label 里面浮点数\caption(例如)。这完全没问题,因为与打印标题相关的计数器已更新标题(及所含的\label)已设置。

相关参考:为什么环境的标签必须出现在标题之后?


2. 我需要编译多少次?

一般来说,\label-\ref系统的工作方式分为两个阶段,因此至少需要两次编译(在第一次迭代期间,在后续编译中可能更少)。在第一\label阶段,标签以以下形式写入.aux文件(假设您不加载任何交叉引用包,例如hyperref):

\newlabel{<label>}{{<reference>}{<page>}

这是一个实际的例子和一次编译后的输出:

在此处输入图片描述

\documentclass{article}
\begin{document}
\section{A section}\label{sec:section}
See Section~\ref{sec:section}.
\end{document}

具体来说,上述 MWE 产生以下内容.aux

\relax 
\@writefile{toc}{\contentsline {section}{\numberline {1}A section}{1}}
\newlabel{sec:section}{{1}{1}}

除了可能与 ToC 相关的内容外,还包含相应的\newlabel。引用本身仍显示为??,因为在编写该内容时不知道引用是什么。为了更好地理解这一点,您应该知道该.aux文件实际上是在 之前读取的\begin{document}。因此,在第一次编译期间,当 TeX 读取 时\ref{<label>},该.aux文件不包含任何引用信息,因此\ref导致??输出为 。

现在,在后续编译期间,会.aux读取\begin{document},因此会将引用(和相应的页码)与特定标签关联起来。这样,当\ref{<label>}遇到 时(在第二阶段),它可以生成正确的引用。

当然,你不需要总是需要两次编译才能获得正确的引用。这是因为特定页面上标签位置的改变不会产生任何不同的输出,因此不需要任何额外的“成对”编译。


3. 那么.aux文件中发生了什么?

正如已经解释过的,每当你写的时候\label{<label>},都会.aux被写入

\newlabel{<label>}{{<reference>}{<page>}}

在页面 shipout 处。但是,这些信息在\begin{document}后续编译期间被读取和执行。并且,从技术角度来看(如果你调查\newlabel和朋友在LaTeX 内核)\label{<label>}创建一个名为 的宏,\r@<label>该宏扩展为{<reference>}{<page>}。并且,根据您使用\ref{<label>}\pageref{<label>},您将收到<reference>(技术上,\@firstoftwo)或<page>(技术上,\@secondoftwo)。


4. 页面引用是什么?

当您使用 时\label,将此信息写入 时.aux实际上会延迟到页面输出。这样做的原因是系统设置为<label>使用 来引用<label>“标题”(通常以数字形式)以及文档中的位置(页面)。由于 TeX 异步收集和优化页面内容,因此已读取的内容可能\label需要等待后续页面写入。因此,不等到页面输出可能意味着与引用关联的页码不正确。

这通常也是为什么人们会混淆编译两次、三次甚至更多次的原因。这背后的真相是,你必须尽可能多地编译,直到引用稳定下来(即引用更改时页码或标签不会发生变化)。这个神奇的数字通常是两次,但也可能更多。

有关突破极限的示例,请参阅文档需要无数次编译器传递吗?


\label5. 影响常规系统\ref的软件包

有许多软件包会影响工作方式\label\ref最值得注意的是hyperref,因为它允许与默认界面集成\label\ref但除了默认参考和页码外还添加了一些其他信息。事实上,当hyperref与上述 MWE 一起使用时

在此处输入图片描述

\documentclass{article}
\usepackage{hyperref}% http://ctan.org/pkg/hyperref
\begin{document}
\section{A section}\label{sec:section}
See Section~\ref{sec:section}.
\end{document}

类似.aux

\relax 
% ... some hyperref stuff
\@writefile{toc}{\contentsline {section}{\numberline {1}A section}{1}{section.1}}
\newlabel{sec:section}{{1}{1}{A section}{section.1}{}}

请注意,它\newlabel仍然具有相同的两个参数格式。但是,{..}与原来的非两个参数相比,第二个参数现在包含 5 个组hyperref。前两个参数是从原始系统继承而来的,而后三个参数是新的。第三个参数包含与特定引用(在本例中为一个部分,因此为部分标题)相关的标题。第四个参数是用于超链接过程的反向特定引用,而第五个参数始终为空(可能是为了以后扩展包本身,因此只是为了安全保存)。


6. 扩展常规\label系统\ref的软件包

这里有一些扩展 LaTeX 交叉引用功能的软件包:

  • hyperref

它允许您包含参考文献的命名标题(主要是因为包括nameref)。此外,它还提供了“自动引用”标签的选项 - 使用\autoref- 插入通常手动添加的前缀(因此变成see \autoref{<label>}see Figure~\ref{<label>}比如说)。

所有常规\labels 仅存储两个值:当前标签和该标签所在的页码(见\newlabel上文)。zref以自然的方式扩展它,以允许存储任意数量的此类特性通过所谓的“属性列表”。此属性列表类似于键值接口,但使用宏,形式为

    \z@newlabel{<label>}{\propA{<propA>}\propB{<propB>}...}

注意\z@-前缀,这明显不同于传统的\newlabel。事实上,在使用 时你仍然可以使用\label- ,或者使用-特定的- 。当然,还有更复杂的标签/引用;请参阅\refzrefzref\zlabel\zrefzref文档更多细节。


针对你的情况:

  • 你有\label \caption- 一个非常常见的问题。因此,\@currentlabel不包含您需要的最新信息,并且会返回不正确的引用。请参阅1\label放置而言。

  • 作为第一次运行,您需要至少编译两次才能使引用稳定下来。请参阅2就汇编数量而言,

  • 在方程式(或任何东西)实际出现在文本中之前引用它。这就是 TeX 的\label-\ref系统的优点;它使用外部文件 ( .aux) 作为编写有关引用的内容以及加载外部文件的位置的中间人。因此,您绝对可以执行以下操作

      %...
      ... see equation~\ref{eqn:myeqn} below:
      \begin{equation}
        f(x) = ax^2 + bx + c \label{eqn:myeqn}
      \end{equation}
      %...
    

...只要你第一次编译至少两次即可。参见2就汇编数量而言。

答案2

物体的标签必须是该对象已定义。因此,如果您要标记标题(在您的示例中),则命令\label必须跟在标题后面或成为标题的一部分。因此,而不是

\label{fig:area_Treasuries}
\caption{Treasuries as a portion of total financial flows.}

你应该使用:

\caption{Treasuries as a portion of total financial flows.}   
\label{fig:area_Treasuries}

或者

 \caption{Treasuries as a portion of total financial flows.\label{fig:area_Treasuries}}

相关内容