Conflicto entre listados e hiperreferencia: se hace referencia a "lstnumber.-14.11" pero no existe

Conflicto entre listados e hiperreferencia: se hace referencia a "lstnumber.-14.11" pero no existe

Veo los siguientes mensajes de error de pdflatex en un proyecto realmente gigantesco:

(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

La parte superior de mi archivo principal se ve así:

\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...

Un ejemplo del \codeblockcuerpo del texto:

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}...

Y un ejemplo de \codeblockref:

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

Desafortunadamente, si junta solo estos fragmentos en un archivo de prueba y los ejecuta, pdflatex test.tex; pdflatex test.tex¡funcionará bien! (Excepto que el hipervínculo en el número "1" en realidad va a la tabla de contenido, no a la página 1.) Pero cuando hago lo mismo en la escala de muchos capítulos, aparece el mensaje de error que se lstnumber.-14.11ve en la parte superior de esta pregunta.

Descubrí que ese lstnumber.-<some number>es el formato de las etiquetas que el paquete genera automáticamente listings, así que supongo que se trata de una mala interacción entre listingsy hyperref. Pero, ¿qué es exactamente lo que está fallando y qué puedo hacer para solucionarlo?


Lo \hspace{1em}de mi \codeblockmacro fue mi ingenuo intento de solucionar el error descrito.aquí, en caso de que ese fuera el problema.

Respuesta1

Aquí está el ejemplo de cómo se debe hacer, en mi opinión:

El comando se aplica antes de que se use la macro, es decir, antes de que se haya aumentado el \codeblockcontador para permitir la referencia. Usar antes es un error muy común y, como tal, la información de referencia cruzada escrita por se usa desde un potencial usado antes. , que podría estar en conjunto con un contador etc., por lo que la información es incorrecta y las coordenadas del hiperancla se toman de una instancia de ancla anterior anterior. De esta manera, los enlaces apuntan a una posición incorrecta.\label\lstinputlistinglistings\refstepcounter\label\refstepcounter\label\refstepcountersection

De hecho, \lstinputlistingtiene una label=opción para especificar el nombre de la etiqueta.

La siguiente es una forma muy reducida proporcionada por personas que no son MWE, pero funciona.

\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}

Respuesta2

En el proceso de publicar esta pregunta, ¡me encontré con la respuesta! (No es que lo entiendapor quéfunciona...)

si junta solo estos fragmentos en un archivo de prueba y los ejecuta pdflatex test.tex; pdflatex test.tex, ¡funciona bien! (Excepto que el hipervínculo en el número "1" en realidad va a la tabla de contenido, no a la página 1).

Cuando arrojaba errores, no me sorprendió que la hiperreferencia fuera al lugar equivocado. Sin embargo, con el caso de prueba reducido, estaba desconcertado. Así que comencé a leer sobreesoproblema y descubrí que lo que quería era \phantomsectionasí:

\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}}

Observe que mi culto a la carga \hspace{1em}ya no es necesario (AFAIK); y pude volver a colocar los caracteres especiales que lst:#1-#2había reemplazado al foo#1#2intentar reducir el caso de prueba.

... ¡Y por arte de magia, de repente mi gigantesco proyecto se compila bien! Ya no hay mensajes de error misteriosos. Todos los enlaces de hiperreferencia van a las páginas correctas y muestran el texto del cuerpo correcto.

No tengo idea de por qué la omisión \phantomsectioncausó tanto estrago, pero después de colocarlo, ¡todo está arreglado!

información relacionada