상호 참조

LaTeX는 문서를 위에서 아래로 딱 한 번 읽습니다. 그래서 2쪽에 \ref{fig:leaf}라고 써도 그 그림이 40쪽에 있다면 번호는 아직 존재하지 않습니다. LaTeX의 상호 참조 장치 전체, 곧 \label\ref는 바로 이 한 가지 문제, 참조가 대상보다 먼저 온다 는 순서 문제를 풀기 위해 만들어졌습니다. 해법은 놀랄 만큼 단순합니다. 첫 실행에서 번호를 .aux 파일에 적어 두고, 두 번째 실행에서 다시 읽어 오는 것입니다. 이 페이지에서는 그 두 번의 컴파일, 중간에 나타나는 굵은 ??, \label\caption 앞에 두면 번호가 어긋나는 이유, 그리고 cleverefvarioref가 가져오는 개선을 차례로 따라갑니다.

\label\ref — 번호 대신 이름으로 부르기

상호 참조는 두 명령만으로 이루어집니다. \label{key} 는 그 지점에서 가장 최근에 증가한 카운터 의 값에 key라는 이름표를 묶고, 지면에는 아무것도 내지 않습니다. \ref{key} 는 그 이름표가 가리키는 번호만 을 넣습니다. 번호를 세는 것은 LaTeX이므로 사용자는 숫자를 한 번도 입력하지 않습니다. key는 자유로운 문자열이고, 이름표가 대상을 따라다니기 때문에 그림 순서를 바꾸거나 절 하나를 통째로 다른 장으로 옮겨도 모든 참조가 따라옵니다. 손으로 “그림 3”이라고 적은 문서는 그런 이동 한 번에 무너지지만, 이쪽은 아무 일도 일어나지 않습니다.

latex
\section{Introduction}
\label{sec:intro}

\begin{equation}
  \label{eq:euler}
  e^{i\pi} + 1 = 0
\end{equation}

\begin{figure}
  \centering
  \includegraphics{leaf}
  \caption{Vein structure of a leaf}
  \label{fig:leaf}          % after \caption, always
\end{figure}

As shown in Section~\ref{sec:intro}, equation~\eqref{eq:euler}
and Figure~\ref{fig:leaf} agree on page~\pageref{fig:leaf}.

거의 모두가 걸려 넘어지는 지점이 하나 있습니다. \ref가 돌려주는 것은 번호뿐 입니다. “그림”, “식”, “절” 같은 말은 따라오지 않으므로 직접 써야 하고, 번호와의 사이는 보통 공백이 아니라 묶음 공백 ~ 로 이어야 합니다. Figure \ref{fig:leaf}라고 쓰면 “Figure”에서 줄이 끝나고 “3”만 다음 줄에 남는 사고가 생기지만, Figure~\ref{fig:leaf}라면 그 자리에서 줄이 나뉘지 않습니다. 종류의 말을 손으로 쓰는 이 작은 수고가 바로 뒤에 나올 \cref\autoref가 대신해 주는 부분입니다.

왜 두 번 컴파일하는가 — .aux 파일과 ??

상호 참조는 한 번의 컴파일로 확정되지 않습니다. LaTeX는 \label을 만날 때마다 그 번호와 페이지를 문서와 같은 기본 이름을 가진 .aux 파일 에 씁니다. 그리고 \ref가 읽을 수 있는 것은 이전 실행이 거기에 넣어 둔 내용뿐입니다. 그래서 첫 번째 실행에서는 참조 대상의 값이 어디에도 없어, 출력에 굵은 ?? 가 나타나고 로그에는 두 가지 경고가 나란히 남습니다. 둘 다 눈에 익혀 둘 가치가 있습니다. 나중에 검색창에 그대로 입력하게 되는 문구이기 때문입니다.

log
LaTeX Warning: Reference `fig:leaf' on page 1 undefined on input line 17.
LaTeX Warning: There were undefined references.
LaTeX Warning: Label(s) may have changed. Rerun to get cross-references right.

??는 사고의 부산물이 아니라 LaTeX 커널에 명시된 규정 입니다. latex.ltx\@setref 매크로는 이름표가 정의되어 있지 않을 때 \reset@font\bfseries ?? 를 조판하고, 바로 다음 줄에서 “Reference … undefined” 경고를 냅니다. 굵은 글씨인 것은 의도적입니다. 굵은 글씨는 주변 서체에 묻히지 않으므로 빈 구멍을 놓칠 수 없습니다. 다시 컴파일하면 .aux의 값이 돌아와 ??가 실제 번호로 바뀝니다. 번호가 밀려 참조값이 바뀌면 경고도 다시 나오므로, 경고가 사라질 때까지 반복하는 것이 올바른 절차입니다. 실무에서는 대개 두 번이면 충분합니다. latexmk는 이 반복을 자동으로 돌리고, Overleaf도 뒤에서 여러 번 처리하므로 그곳에서 ??를 보는 일은 드뭅니다.

.aux는 평범한 텍스트 파일이므로 열어서 그대로 읽을 수 있습니다. 이름표 하나마다 \newlabel 행이 하나 기록되고, 그 안에는 다섯 개의 필드 가 들어 있습니다. 번호, 페이지, 제목 문자열, 링크 대상 앵커 이름, 그리고 예비 필드 하나입니다. 세 번째 필드가 있기에 \nameref는 제목 자체를 넣을 수 있고, 네 번째 필드가 있기에 hyperref는 클릭이 어디로 가야 할지 압니다. 참조가 이상한데 원인을 모르겠다면 .aux를 열어 그 행이 있는지 보는 것이 가장 빠릅니다. 행 자체가 없으면 \label이 아예 잡히지 않은 것이고, 값이 이상하면 놓아 둔 자리의 문제, 곧 다음 절의 주제입니다.

mydoc.aux
% one line per label: {number}{page}{title}{anchor}{spare}
\newlabel{sec:intro}{{1}{1}{Introduction}{section.1}{}}
\newlabel{fig:leaf}{{2}{3}{Vein structure of a leaf}{figure.2}{}}

\ref가 엉뚱한 번호를 낼 때 — \label\caption 뒤에

그림 참조가 그림 번호와 맞지 않는 증상. 원인은 거의 예외 없이 \label을 둔 자리입니다. \labelfigure 환경 안에 있다는 이유로 그림 번호를 잡는 것이 아닙니다. 잡는 것은 바로 앞에서 증가한 카운터 의 값이며, figure 환경 자체는 어떤 카운터도 증가시키지 않습니다. 카운터를 올리는 것은 \caption 입니다. 따라서 \begin{figure} 바로 뒤에 쓴 \label은 그림 번호가 아니라 그 시점에 마지막으로 증가한 카운터, 대개는 지금 있는 절이나 장의 번호를 잡아 버립니다.

설명보다 직접 돌려 보는 편이 빠릅니다. 일곱 번째 절 안에 그림을 하나 두고 \caption 에 각각 이름표를 붙여 TeX Live 2024의 pdfLaTeX으로 컴파일하면 .aux에는 이렇게 기록됩니다. 앞에 둔 이름표는 7, 곧 절 번호이고, 뒤에 둔 이름표는 1, 곧 그림 번호입니다. 그런데 경고는 하나도 나오지 않습니다. 둘 다 있을 법한 번호이므로 LaTeX으로서는 어느 쪽이 틀렸는지 판단할 방법이 없습니다. 오류로 멈춰 주지 않기 때문에 이 사고는 검토를 지나 인쇄까지 도달합니다.

latex
\section{A}\section{B}\section{C}
\section{D}\section{E}\section{F}\section{G}   % we are now in section 7

\begin{figure}
  \label{fig:before}      % WRONG: no counter stepped yet -> picks up 7
  \centering\rule{2cm}{1cm}
  \caption{A leaf}        % <- this is what steps the figure counter
  \label{fig:after}       % RIGHT: picks up 1
\end{figure}

% .aux after two runs:
%   \newlabel{fig:before}{{7}{1}{}{}{}}
%   \newlabel{fig:after}{{1}{1}{}{}{}}

규칙은 한 줄로 줄어듭니다. \label은 번호를 만들어 내는 명령 바로 뒤에 둡니다. 그림과 표라면 \caption 뒤(그 인수 안에 써도 괜찮습니다), 제목이라면 \section 계열 바로 뒤, 번호 붙은 수식이라면 equation 환경 안, 목록 항목이라면 \item 뒤입니다. 캡션이 여럿인 그림에 이름표를 하나만 붙이면 어느 \caption 뒤에 두었는지에 따라 가리키는 번호가 달라집니다. 그리고 \label\caption 에 쓸 정당한 이유는 애초에 \caption이 없는 경우뿐이라고 생각해도 무방합니다.

\pageref와 이름표 짓는 법

번호가 아니라 페이지 를 가리키고 싶을 때는 \pageref{key} 를 씁니다. 같은 이름표를 받아 그 \label조판된 페이지의 번호 를 돌려주므로 Figure~\ref{fig:leaf} on page~\pageref{fig:leaf}처럼 번호와 페이지를 함께 적을 수 있습니다. 구조로 보면 \newlabel 행의 두 번째 필드가 그대로 돌아오는 것입니다. 독자가 실제로 책장을 넘기는 문서, 곧 긴 보고서나 제본된 논문에서 진가를 발휘합니다.

key는 마음대로 지을 수 있지만, 가리키는 대상의 종류 를 접두사로 붙이는 방식이 널리 쓰입니다. sec: fig: tab: eq: ch: lst: 같은 식입니다. 효과는 둘입니다. 첫째, fig:leaf처럼 내용으로 이름을 붙여 두면 그림 순서를 바꿔도 이름을 다시 지을 필요가 없습니다. fig:3 같은 이름은 두 번째 그림을 끼워 넣는 순간 거짓이 됩니다. 둘째, \ref{fig:...}만 봐도 참조 대상의 종류를 알 수 있어, 나중에 문서를 \cref로 옮길 때 자기 소스를 기계적으로 훑어 읽을 수 있습니다.

접두사가리키는 대상
ch:장(\chapter)
sec:절과 소절(\section, \subsection)
fig:그림(figure\caption 뒤)
tab:표(table\caption 뒤)
eq:번호 붙은 수식(equation 등의 안)
lst:코드 목록(listings\caption 뒤)

\eqref — 수식 번호에 괄호를 붙여 준다(amsmath)

수식 번호는 관례상 괄호를 붙여 씁니다(“식 (3)으로부터”). 그러나 기본 \ref3만 돌려줍니다. amsmath를 읽으면 쓸 수 있는 \eqref{key} 는 괄호를 보충해 (3)을 돌려줍니다. 여기서 진짜 이득은 타이핑 수고가 아니라 글꼴 입니다. \eqref가 만드는 괄호는 주변 글꼴과 무관하게 항상 직립체로 조판되므로, 본문이 이탤릭인 정리 환경 안에서도 괄호만은 곧게 섭니다. (\ref{eq:euler})라고 손으로 쓰면 바로 그 괄호가 이탤릭을 따라 기울어집니다.

cleveref\cref\Cref가 말도 단복수도 알아서

cleveref는 참조를 한 단계 끌어올립니다. \cref{key} 는 대상의 종류를 나타내는 말을 자동으로 앞에 붙이고(기본은 줄임말 “fig. 1”, noabbrev 옵션을 쓰면 “figure 1”), \Cref{key} 는 그 첫 글자를 대문자로 만들어 문장을 열 수 있게 합니다. 진짜 강점은 여러 개와 범위 입니다. \cref{fig:a,fig:b,fig:c}처럼 공백 없이 쉼표로 구분해 넘기면 번호를 정렬하고 이어 붙이며, 그 과정에서 말까지 복수형으로 바꾸어 “figs. 1, 2 and 4” 같은 결과를 냅니다. 게다가 번호가 연속이면 자동으로 범위로 접히므로 위의 셋은 “figs. 1 to 3”이 됩니다. \crefrange{first}{last} 는 같은 축약을 양 끝 이름표만 적어서 얻는 명령입니다.

앞에 붙는 말은 \crefname{type}{단수}{복수} 로 다시 정의합니다(첫 글자 대문자 판은 \Crefname). 현지화도 이 방법으로 하며, 한국어라면 단수와 복수에 같은 말을 주어 \crefname{figure}{그림}{그림} 처럼 씁니다. 문서 전체에서 항상 대문자로 하고 싶다면 capitalise 옵션과 함께 불러옵니다. 반대로 말 없이 번호만 필요한 자리, 예를 들어 괄호 안이나 표의 칸에서는 \labelcref{key} 를 쓰면 기본 \ref와 똑같은 결과를 얻습니다.

읽는 순서에는 절대적인 규칙이 있습니다. cleverefhyperrefvariorefamsmath보다 뒤이며, 세 가지 모두를 검사합니다. cleverefhyperref가 정의한 것을 감지해 자기 명령을 짜므로 순서가 뒤집히면 성립하지 않습니다. 다행히 이것은 조용히 깨지지 않습니다. TeX Live 2024에 들어 있는 cleveref.sty\begin{document} 시점에 순서를 검사해 아래와 같이 분명하게 멈춥니다. 다만 varioref를 함께 쓰는 경우는 다릅니다. cleveref 매뉴얼은 varioref → hyperref → cleveref 순서를 지정하면서, 순서를 틀리면 출력에도 로그에도 경고 없이 참조가 전혀 다른 대상을 가리킬 수 있다고 경고합니다.

latex
\usepackage{varioref}
\usepackage{hyperref}
\usepackage{cleveref}   % always last of the three

% If cleveref is loaded before hyperref, TeX Live 2024 stops with:
%   ! Package cleveref Error: cleveref must be loaded after hyperref!.
%   Package load order is wrong: load cleveref *after* hyperref.

\cref{fig:a,fig:b,fig:c}       % figs. 1 to 3   (consecutive: compressed)
\cref{eq:euler,eq:max}         % eqs. (1) and (4)
\Cref{sec:intro} explains ...  % Section 1 explains ...
\labelcref{fig:a}              % 1   (number only, like \ref)

% with \usepackage[noabbrev]{cleveref} the same lines give
%   figures 1 to 3 / equations (1) and (4)

varioref — “다음 페이지의 그림”이라고 써 준다

제본된 문서에서는 기계적으로 “12쪽의 그림 3”이라고 쓰기보다 가까우면 “다음 페이지의 그림 3”, 펼침면 반대쪽이면 “맞은편 페이지의 그림 3”이라고 쓰는 편이 자연스럽습니다. varioref\vref{key}\ref와 같은 번호를 내면서 참조하는 곳과 대상의 페이지 관계를 살펴 알맞은 문구를 덧붙입니다. 같은 페이지라면 아무것도 붙이지 않습니다. 페이지 안내만 필요하다면 \vpageref{key} 가 그 일만 하며, 두 개의 선택 인수로 같은 페이지일 때의 문구와 다른 페이지일 때의 앞말을 각각 지정합니다.

이 영리함에는 대가가 있습니다. \vref가 무엇을 낼지는 조판 결과, 곧 어느 페이지에 놓였는지에 달려 있고, 그 출력의 길이가 다시 페이지 나눔 위치를 움직일 수 있습니다. 그래서 값이 자리 잡을 때까지 추가 컴파일 이 필요할 수 있습니다. 로그에 “Rerun to get cross-references right”가 계속 나온다면 대개 이것이 원인입니다. cleveref와 함께 불러오면 \vref는 cleveref의 서식으로 조판되므로, 둘 다 쓴다면 순서(varioref → hyperref → cleveref)를 지키고 문서 전체를 \cref 계열로 통일하는 편이 신경 쓸 일이 적습니다.

latex
\usepackage{varioref}

See~\vref{fig:leaf}.
%   same page : See figure 3.
%   next page : See figure 3 on the next page.
%   far away  : See figure 3 on page 12.

The data is summarised \vpageref[above][]{tab:data}.

무엇을 고를지 망설여진다면 실무적인 답은 문서 전체를 cleveref로 통일하는 것 입니다. 종류의 말도, 단복수도, 여러 참조도, 범위도 알아서 처리하므로 대상이 표인데 Figure~\ref{tab:...} 라고 쓰는 고전적인 실수가 원리적으로 생기지 않습니다. \ref\pageref는 구조를 이해하는 데 여전히 필수이고, \eqref는 수학에서, \vref는 제본된 작업물에서 각각 지금도 제 몫을 합니다. 아래 표는 각각이 무엇을 출력하는지 정리한 것입니다.

명령출력제공
\label{key}방금 증가한 카운터에 이름표를 붙임. 출력 없음LaTeX 커널
\ref{key}번호만(예: 3)LaTeX 커널
\pageref{key}그 이름표가 조판된 페이지 번호LaTeX 커널
\eqref{key}직립 괄호가 붙은 수식 번호(예: (3))amsmath
\autoref{key}종류의 말 + 번호, 전체가 링크(예: Figure 3)hyperref
\nameref{key}대상 제목의 문자열 자체hyperref
\vref{key}번호 + 페이지 안내(“다음 페이지에” 등)varioref
\cref{key}종류의 말 + 번호. 목록, 범위, 단복수 자동 처리cleveref
\Cref{key}첫 글자를 대문자로 한 \cref. 문장 첫머리용cleveref
\crefrange{a}{b}연속 범위(예: figures 1 to 3)cleveref
\labelcref{key}번호만. 종류의 말이 없는 \crefcleveref