Конфликт между списками и гиперссылкой: ссылка на "lstnumber.-14.11" есть, но она не существует

Конфликт между списками и гиперссылкой: ссылка на "lstnumber.-14.11" есть, но она не существует

Я вижу следующие сообщения об ошибках от pdflatex в действительно гигантском проекте:

(see the transcript file for additional information)pdfTeX warning (dest): name
{lstnumber.-14.11} has been referenced but does not exist, replaced by a fixed 
one

pdfTeX warning (dest): name{lstnumber.-18.22} has been referenced but does not 
exist, replaced by a fixed one

pdfTeX warning (dest): name{lstnumber.-9.40} has been referenced but does not e
xist, replaced by a fixed one

pdfTeX warning (dest): name{lstnumber.-4.3} has been referenced but does not ex
ist, replaced by a fixed one

Верхняя часть моего основного файла выглядит так:

\documentclass[ebook,10pt,oneside,final]{memoir}
\usepackage{microtype}

% support for code listings
\usepackage[final]{listings}
\include{autodedent}
\lstset{
  basicstyle=\ttfamily\footnotesize,
  numberstyle=\footnotesize,
  breaklines=true,
  numbers=left,
  firstnumber=1,
  rangeprefix=//,
  includerangemarker=false
}

% support for indexing
\usepackage{makeidx}
\makeindex

% make _ a non-special character
\usepackage{underscore}

% support for cross-references
\usepackage{hyperref}
% \newcommand{\href}[2]{#2}

% fix spacing in \tableofcontents
\renewcommand\partnumberline[1]{#1\hspace{1em}}

% custom commands for use in the text of the book itself
\newcommand{\newterm}[1]{\textit{#1}}
\newcommand{\code}[1]{\mbox{\lstinline[basicstyle=\ttfamily]$#1$}}
\newcommand{\slurl}[1]{\href{https://#1}{\textsl{#1}}}
\newcommand{\codeblock}[2]{\label{foo#1#2}\hspace{1em}\lstinputlisting[linerange=ex#2-dex#2,autodedent]{examples-ch#1.cc}}
\newcommand{\codeblockref}[2]{\pageref{foo#1#2}}
\newcommand{\Csharp}{C\#}

\begin{document}

\frontmatter
\include{preface}
\tableofcontents

\mainmatter

% ...and so on...

Пример \codeblockиз основного текста:

Let's write a function to multiply each of the elements
in an array by 2.

\codeblock{1}{1}

Our function \code{double_each_element} works \emph{only} with objects of type
\code{array_of_int}...

И пример \codeblockref:

Compare this version of the code to the version on page
\codeblockref{1}{1}.

К сожалению, если вы соберете только эти фрагменты в тестовом файле и запустите pdflatex test.tex; pdflatex test.tex— все будет работать отлично! (За исключением того, что гиперссылка на цифру «1» на самом деле ведет к оглавлению, а не на страницу 1.) Но когда я делаю то же самое в масштабе многих глав, я получаю сообщения об ошибках, которые lstnumber.-14.11вы видите в начале этого вопроса.

Я выяснил, что lstnumber.-<some number>это формат меток, которые автоматически генерируются пакетом listings, поэтому я предполагаю, что это какое-то плохое взаимодействие между listingsи hyperref. Но что именно идет не так и что я могу сделать, чтобы это исправить?


В \hspace{1em}моем \codeblockмакросе была моя наивная попытка обойти описанную ошибкуздесь, на случай, если проблема была именно в этом.

решение1

Вот пример того, как это следует делать, по моему мнению:

В \codeblockкоманда \labelприменяется до \lstinputlistingиспользования макроса, т. е. до того, как счетчик listingsбыл увеличен для возможности ссылки с \refstepcounter-- использование \labelbefore \refstepcounterявляется очень распространенной ошибкой, и, как таковая, информация перекрестной ссылки, записанная с помощью, \labelиспользуется из потенциально \refstepcounterиспользуемого before, который может быть связан с sectionetc. counter, поэтому информация неверна, и координаты гиперякоря берутся из более старого экземпляра якоря before. Таким образом, ссылки указывают обратно на неправильную позицию.

На самом деле, \lstinputlistingесть label=возможность указать имя метки.

Ниже приведена очень сокращенная форма, предложенная не-MWE, но она работает.

\documentclass[ebook,10pt,oneside,final]{memoir}
\usepackage{microtype}

% support for code listings

\begin{filecontents}{examplehelloworld.c}
#include<stdio.h>

int main(int argc,char **argv)
{
  printf("Hello World!\n");
  return(0);
}
\end{filecontents}

\usepackage[final]{listings}
%\include{autodedent}
\lstset{
  basicstyle=\ttfamily\footnotesize,
  numberstyle=\footnotesize,
  breaklines=true,
  numbers=left,
  firstnumber=1,
  rangeprefix=//,
  includerangemarker=false
}

% support for indexing
\usepackage{makeidx}
\makeindex

% make _ a non-special character
\usepackage{underscore}

% support for cross-references
\usepackage{hyperref}
% \newcommand{\href}[2]{#2}

% fix spacing in \tableofcontents
\renewcommand\partnumberline[1]{#1\hspace{1em}}

% custom commands for use in the text of the book itself
\newcommand{\newterm}[1]{\textit{#1}}
\newcommand{\code}[1]{\mbox{\lstinline[basicstyle=\ttfamily]$#1$}}
\newcommand{\slurl}[1]{\href{https://#1}{\textsl{#1}}}
\newcommand{\codeblock}[2]{\hspace{1em}\lstinputlisting[language={C},label={lst:#1-#2}]{examplehelloworld.c}}
\newcommand{\codeblockref}[2]{\pageref{lst:#1-#2}}
\newcommand{\Csharp}{C\#}


\usepackage{blindtext}

\begin{document}

\frontmatter
%\include{preface}
\tableofcontents

\mainmatter


\blindtext[3]


Reference: \codeblockref{1}{4}

\blindtext[5]


\codeblock{1}{4}



\end{document}

решение2

В процессе публикации этого вопроса я наткнулся на ответ! (Не то чтобы я его понял)почемуоно работает...)

Если вы соберете только эти фрагменты в тестовом файле и запустите pdflatex test.tex; pdflatex test.tex— все будет работать отлично! (За исключением того, что гиперссылка под номером «1» на самом деле ведет в оглавление, а не на страницу 1.)

Когда он выдавал ошибки, я не был удивлен, что hyperref попал не туда. Однако с сокращенным тестовым случаем я был озадачен. Поэтому я пошел читать очтопроблема, и обнаружил, что то, что я хотел, было \phantomsection, например, таким:

\newcommand{\codeblock}[2]{\phantomsection\label{lst:#1-#2}\lstinputlisting[linerange=ex#2-dex#2,autodedent]{examples-ch#1.cc}}
\newcommand{\codeblockref}[2]{\pageref{lst:#1-#2}}

Обратите внимание, что мой карго-культ \hspace{1em}больше не нужен (насколько мне известно); и я смог вернуть специальные символы, lst:#1-#2которые заменил, foo#1#2пытаясь сократить тестовый пример.

...И по волшебству мой гигантский проект внезапно компилируется отлично! Больше никаких загадочных сообщений об ошибках. Все гиперссылки ведут на нужные страницы и показывают правильный основной текст.

Понятия не имею, почему пропуск \phantomsectionвызвал такой хаос, но после его добавления все исправилось!

Связанный контент