\setcounter und \setlength sehen gleich aus und verhalten sich entgegengesetzt. Führt man beide innerhalb einer Gruppe aus, behält der Zähler nach dem Schließen seinen neuen Wert, während die Länge stillschweigend zurückspringt – denn nur eine der beiden Definitionen im Kernel trägt das Wort \global. Diese Seite behandelt die beiden numerischen Register von LaTeX: Zähler (\newcounter), die eine ganze Zahl halten und jede Kapitel-, Abbildungs- und Gleichungsnummer antreiben, und Längen (\newlength), die eine Dimension halten und sich als Glue-Register statt als bloße Dimensionen entpuppen. Unterwegs: warum ein \label direkt nach \stepcounter klammheimlich auf eine fremde Nummer verweist, wozu \value tatsächlich expandiert und wie mit \dimexpr, calc und \fpeval gerechnet wird – Umrechnungen wie 1in = 72,27pt und 1pt = 65536sp inbegriffen.
Zähler mit \newcounter anlegen und bewegen
Ein neuer Zähler entsteht mit \newcounter{foo}. Der Name ist eine schlichte Zeichenkette ohne Backslash, und der Wert direkt nach der Erzeugung ist 0. Darunter steckt ein \count-Register von TeX – \meaning antwortet mit etwas wie \count196. Drei Befehle ändern den Wert: \setcounter{foo}{3} weist zu, \addtocounter{foo}{2} addiert (eine negative Zahl subtrahiert), und \stepcounter{foo} erhöht um genau 1. Das optionale zweite Argument \newcounter{foo}[⟨parent⟩] ordnet foo dem Zähler parent unter, sodass foo bei jeder Erhöhung von parent auf 0 zurückfällt. Genau das steckt hinter dem Neubeginn der Unterabschnittsnummern beim Abschnittswechsel.
\newcounter{trial} % created with value 0
\setcounter{trial}{5} % trial = 5
\addtocounter{trial}{-2} % trial = 3
\stepcounter{trial} % trial = 4, and every child counter resets
\newcounter{item}[section] % "item" restarts at 0 whenever section steps
% errors you will actually see
\setcounter{nosuch}{3} % ! LaTeX Error: No counter 'nosuch' defined.
\newcounter{trial} % ! LaTeX Error: Command \c@trial already defined.
\setcounter{trial}{} % ! Missing number, treated as zero.Der genaue Wortlaut der Fehler lohnt das Merken. Ein nicht existierender Zähler ergibt ! LaTeX Error: No counter 'nosuch' defined.; zweimal \newcounter auf denselben Namen ergibt ! LaTeX Error: Command \c@trial already defined. Das dort genannte \c@trial ist das interne Register, das trial tatsächlich hält – und weil der Name ein @ enthält, braucht man aus der Präambel heraus \makeatletter. Das Zurücksetzen übernimmt das interne Makro \@stpelt, dessen Rumpf das Kind auf −1 setzt und dann \stepcounter darauf aufruft. Erhöhen statt schlicht 0 zuzuweisen ist genau der Kniff, mit dem sich das Zurücksetzen bis zu den Enkelzählern fortpflanzt.
\stepcounter gegen \refstepcounter: wenn \label auf eine fremde Nummer zeigt
\refstepcounter{foo} erhöht und setzt genauso zurück wie \stepcounter und macht darüber hinaus foo zu der Nummer, auf die sich gerade verweisen lässt. Ohne diesen Zusatzschritt hat \label nichts, woran es sich halten könnte. Gemessen ist das Symptom bösartiger als vermutet. In einem Dokument mit drei Abschnitten steht demo nach \stepcounter{demo}\label{bad} bei 1 – in der .aux-Datei landet aber \newlabel{bad}{{3}{1}{}{}{}}, sodass \ref{bad} eine 3 ausgibt, die Nummer des vorangehenden Abschnitts. Das Label fällt nicht auf den vorherigen Wert des Zählers zurück, sondern klammert sich an den Zähler, den \refstepcounter zuletzt angefasst hat – gewöhnlich ein völlig anderer. Und es gibt weder Fehler noch Warnung. Dasselbe ganz am Anfang eines Dokuments ergibt \newlabel{step}{{}{1}{}{}{}}, und \ref druckt überhaupt nichts.
\newcounter{demo}
\begin{document}
\section{First}\section{Second}\section{Third}
Here: \stepcounter{demo}\label{bad} (demo is now \thedemo)
Reference: \ref{bad}
\end{document}
% .aux -> \newlabel{bad}{{3}{1}{}{}{}}
% output -> "Here: (demo is now 1)" / "Reference: 3"
% log -> 0 errors, 0 warnings
% the fix -> \refstepcounter{demo}\label{good} gives \ref = 1Der Mechanismus ist in latex.ltx offensichtlich. \refstepcounter ruft \stepcounter auf und schreibt danach den Wert von \thefoo in \@currentlabel; \label tut nichts anderes, als \@currentlabel in die .aux-Datei zu kopieren. \label speichert also nie „den Zähler unmittelbar davor“, sondern den aktuellen Wert einer globalen Variablen. LaTeX selbst verwendet \refstepcounter, wenn es section, equation oder figure erhöht – deshalb liefert ein \label an einer Überschrift oder Gleichung die richtige Nummer. Die praktische Regel folgt sofort: \stepcounter, wenn eine Zahl nur intern weiterlaufen soll, und \refstepcounter, wenn ein nummeriertes Ding entsteht, auf das \label verweisen können soll. Wenn eine selbstgebaute Satzumgebung oder Aufgabennummer sich nicht korrekt referenzieren lässt, hier zuerst nachsehen.
\value: einen Zähler als rechenbare Zahl herausholen
\value{foo} expandiert zu genau dem \count-Register, das den Zähler hält – die Kerneldefinition ist buchstäblich die eine Zeile \csname c@#1\endcsname. Deshalb funktioniert es im Wertargument von \setcounter und \addtocounter, in einem \ifnum-Vergleich, in einem \numexpr-Ausdruck – überall dort, wo LaTeX eine ganze Zahl erwartet. Umgekehrt folgt daraus: \value ist kein Ausgabebefehl. Eine Zahl in den Text zu setzen ist Aufgabe von \arabic oder \thefoo im nächsten Abschnitt; \value liefert stets nur die rohe Zahl zum Rechnen. Hält man die beiden Rollen auseinander, verschwinden die Verwirrungen „meine Nummer erscheint nicht“ und „die Ziffer kam doppelt“.
\setcounter{bar}{\value{foo}} % copy foo into bar
\addtocounter{bar}{\value{foo}} % bar = bar + foo
\ifnum\value{page}>10 \dots\fi % compare
\setcounter{bar}{\numexpr\value{foo}*2+1\relax} % arithmetic, no package
% \value is NOT for printing:
\value{foo} % wrong -- prints nothing useful
\arabic{foo} % right
\thefoo % right, and honours any format you definedDas Aussehen einer Nummer ändern – von \arabic bis \thefoo
Sechs Befehle verwandeln den Wert eines Zählers in gedruckte Zeichen, jeder nimmt einen Zählernamen als Argument. Die Nummer, die man tatsächlich sieht, kommt jedoch aus \thefoo, einem eigenen Makro, das jeder Zähler automatisch erhält: section hat \thesection, figure hat \thefigure, und eine Umdefinition mit \renewcommand ändert das gesamte Zahlenformat auf einen Schlag. \alph und \Alph bilden auf die 26 Buchstaben ab. Die Grenze ist feiner, als sie aussieht: eine 0 gibt gar nichts aus und löst keinen Fehler aus, während negative Werte und alles über 26 den Fehler ! LaTeX Error: Counter too large. ergeben. \fnsymbol hat ebenfalls den gültigen Bereich 1–9, und eine 10 löst denselben ! LaTeX Error: Counter too large. aus. Eine Korrektur zu älteren Ratschlägen sei angebracht: Im mit TeX Live 2024 ausgelieferten LaTeX2e ist \@fnsymbol in jedem Fall mit \TextOrMath definiert, weshalb \fnsymbol unmittelbar im laufenden Text funktioniert – die Hülle $\fnsymbol{footnote}$ ist nicht mehr nötig (für Fußnoten bleibt \thefootnote der übliche Weg).
| Befehl | Ausgabe | Bereich / Hinweise |
|---|---|---|
\arabic | 1, 2, 3 … | Standard; auch negative Werte werden gedruckt |
\roman | i, ii, iii … | Unter 1 wird nichts ausgegeben |
\Roman | I, II, III … | Unter 1 wird nichts ausgegeben |
\alph | a, b, c … | 1–26. 0 gibt nichts aus; negative Werte und ab 27 Counter too large |
\Alph | A, B, C … | 1–26. 0 gibt nichts aus; negative Werte und ab 27 Counter too large |
\fnsymbol | ∗ † ‡ § ¶ ‖ ∗∗ †† ‡‡ | 1–9; 10 ergibt Counter too large. Funktioniert im Fließtext, ohne Mathe-Hülle |
\thefoo | Das offizielle Format des Zählers | Das wird tatsächlich gedruckt; per \renewcommand ändern |
\renewcommand{\thesection}{\Roman{section}} % 1, 2, 3 -> I, II, III
\renewcommand{\thefigure}{\thesection.\arabic{figure}} % figure 2.3
\renewcommand{\thefootnote}{\fnsymbol{footnote}} % footnotes as * dagger ...
% appendix figures as A.1, A.2, ...
\appendix
\renewcommand{\thefigure}{\Alph{section}.\arabic{figure}}Wie im zweiten Beispiel erzeugt das Einweben der Ausgabe eines anderen Zählers in eine \the…-Definition zusammengesetzte Nummern wie „2.3“. Daran zeigt sich das Entwurfsprinzip: Das Aussehen einer Nummer (die Definition von \thefigure) und die Kopplung, die über das Zurücksetzen entscheidet (das Elternargument von \newcounter), werden völlig getrennt festgelegt. Ein bloßes \renewcommand{\thefigure}{\thesection.\arabic{figure}} lässt Abbildungsnummern deshalb nicht bei jedem Abschnitt neu beginnen – dafür muss zusätzlich die Eltern-Kind-Beziehung eingerichtet werden, etwa mit \counterwithin{figure}{section}.
Die Standardzähler und secnumdepth / tocdepth als Konfigurationswerte
LaTeX definiert eine Reihe von Zählern vor und treibt sie beim Lesen des Dokuments automatisch an. Auch diese lassen sich mit \setcounter anfassen – so nummeriert man Kapitel mittendrin neu oder lässt Abbildungen im Anhang als A.1 erscheinen. Legt man in einem leeren article einen einzigen Zähler an, landet dessen internes Register bei etwa \count196 – etliche Dutzend Standardzähler laufen also bereits. Klassisches TeX erlaubte nur 256 Register je Art; e-TeX hob diese Grenze an, weshalb heute 400 hintereinander angelegte Zähler ohne jede Beschwerde durchgehen (der letzte landete auf \count662).
- Gliederung:
part,chapter,section,subsection,subsubsection,paragraph,subparagraph(welche existieren, hängt von der Klasse ab) - Gleitobjekte und Formeln:
figure,table,equation - Fußnoten:
footnote,mpfootnote(Fußnoten innerhalb einerminipage) - Listen:
enumi,enumii,enumiii,enumiv(die vier Verschachtelungsebenen vonenumerate) - Seite:
page - Konfigurationswerte:
secnumdepth(bis zu welcher Tiefe nummeriert wird) undtocdepth(bis zu welcher Tiefe Einträge ins Inhaltsverzeichnis gelangen)
Die letzten beiden sind anderer Natur: ganzzahlige Stellräder, die bestimmen, wie „tief“ Nummerierung und Inhaltsverzeichnis reichen – gezählt wird damit nichts. Jeder Gliederungsbefehl hat eine Ebenennummer (section ist 1, subsection ist 2 …), und eine Ebene wird nur nummeriert, solange diese Zahl kleiner oder gleich secnumdepth ist. Der Standard liegt bei etwa 2, weshalb \setcounter{secnumdepth}{1} die Nummern unterhalb der Abschnittsebene entfernt und \setcounter{tocdepth}{1} das Inhaltsverzeichnis auf Abschnitte zusammenstreicht. Die beiden zeigen es deutlich: Ein Zähler ist nicht nur ein Zählwerk, sondern auch ein Konfigurationswert, der den Satz steuert.
\newlength legt ein Skip-Register an, kein Dimen
Unter \newlength{\mylen} steckt \newskip. Die Kerneldefinition ist die einzelne Zeile \@ifdefinable#1{\newskip#1}, und \meaning bestätigt es mit einer Antwort wie \skip50. Das ist wesentlich, denn ein Skip-Register kann Dehnung und Stauchung tragen – deshalb ist \setlength{\parskip}{1em plus 2pt minus 1pt} eine völlig legale Zuweisung. Gemessen meldet \the\parskip daraufhin 10.00002pt plus 2.0pt minus 1.0pt, alle drei Komponenten bleiben erhalten. Anders als bei einem Zähler ist das Argument ein Befehlsname mit Backslash (\mylen), der Anfangswert ist 0pt. Zweimal derselbe Name ergibt ! LaTeX Error: Command \mylen already defined. Und weil \a, \b, \c, \d und \t bereits als Akzentbefehle existieren, geht \newlength{\a} genau deshalb nicht durch.
\newlength{\gap}
\setlength{\gap}{20pt plus 10pt minus 5pt} % a rubber length in a register
% watch the stretch and shrink actually being used
\showboxbreadth=5 \showboxdepth=5
\setbox0=\hbox to 70pt{\rule{20pt}{2pt}\hspace{\gap}\rule{20pt}{2pt}}\showbox0
\setbox1=\hbox to 55pt{\rule{20pt}{2pt}\hspace{\gap}\rule{20pt}{2pt}}\showbox1
% log: \hbox(2.0+0.0)x70.0, glue set 1.0 <- all 10pt of "plus" used
% \hbox(2.0+0.0)x55.0, glue set - 1.0 <- all 5pt of "minus" usedMit \showbox lässt sich das Dehnen und Stauchen direkt aus dem Log ablesen. Zwingt man eine Box natürlicher Breite 60pt auf 70pt, erscheint glue set 1.0 – das gesamte plus 10pt wurde aufgebraucht. Presst man sie auf 55pt, erscheint glue set - 1.0, das ganze minus 5pt ist verbraucht. Dieser glue set-Wert ist ein starker Verbündeter bei Layoutuntersuchungen: Steht dort 2 oder 3, wird die Box weit über das Bequeme hinaus gedehnt. Wie plus und minus über eine ganze Seite hinweg wirken – die Geschichte von \fill und \flushbottom – behandelt ausführlich die Seite über Längen und Abstände.
Warum \setcounter global und \setlength lokal wirkt
Der Grund ist ein einziges Wort in den Definitionen von latex.ltx. \setcounter und \addtocounter tragen \global, \setlength und \addtolength nicht. Dieser eine Unterschied erzeugt völlig verschiedenes Verhalten. Ändert man Zähler und Länge in derselben Gruppe, so behält der Zähler nach dem Schließen seinen neuen Wert, während die Länge auf den alten zurückgesprungen ist – gemessen sprang eine von 1cm auf 9cm gesetzte Länge im Moment des Gruppenendes auf 28.45274pt (also 1cm) zurück. Die Asymmetrie ist sinnvoll: Eine Kapitelnummer ist Dokumentzustand, der beim Ende einer Umgebung nicht verloren gehen darf, während eine vorübergehende Randanpassung nur im eigenen Abschnitt gelten soll.
\newcounter{cnt}\newlength{\len}
\setcounter{cnt}{1}\setlength{\len}{1cm}
{\setcounter{cnt}{99}\setlength{\len}{9cm}%
inside the group: cnt=\thecnt\ len=\the\len} % 99 / 256.0748pt
after the group: cnt=\thecnt\ len=\the\len % 99 / 28.45274pt
% latex.ltx:
% \def\setcounter#1#2{... {\global\csname c@#1\endcsname#2\relax}}
% \def\setlength#1#2{#1 #2\relax} <- no \global
% to make a length assignment survive a group:
\global\setlength{\len}{9cm}Dieser Unterschied wird bedeutsam, sobald man eigene Werkzeuge mit \newcommand oder \newenvironment schreibt. Ein \setlength{\parindent}{0pt} innerhalb einer Umgebung wird bei \end automatisch zurückgenommen – kein Aufräumen nötig. Umgekehrt braucht es \setcounter (oder ein ausdrückliches \global), damit eine in der Umgebung ermittelte Zahl außerhalb überlebt. Die beiden klassischen Fehler – „meine Einstellung war nach der Umgebung verschwunden“ und „meine Randänderung ist nach außen durchgesickert“ – erklären sich beide aus dem Vorhandensein oder Fehlen dieses einen Wortes. Dass eine Umgebung überhaupt eine Gruppe bildet, behandelt die Seite über das Schreiben von Umgebungen.
Mit Längen rechnen: \dimexpr, calc, \fpeval und die Einheitenumrechnung
Von Addition, Multiplikation und Division lassen sich ganz ohne Paket die e-TeX-Primitive \numexpr und \dimexpr schreiben. In einem voreingestellten article liefert \the\dimexpr\textwidth/3\relax den Wert 115.0pt, und \the\dimexpr 2cm+4pt\relax ergibt 60.9055pt. Ein Vorbehalt: Die Division in \numexpr rundet, sie schneidet nicht ab – \the\numexpr 7/2\relax ist 4 und -7/2 ist −4. Wer eine LaTeX-nähere Schreibweise möchte, lädt das Paket calc, mit dem ein Ausdruck wie \setlength{\x}{(\textwidth - 2em)/2} direkt in \setlength stehen darf (gemessen: 162.49998pt). Nur das Skalieren mit einem reellen Faktor wird anders geschrieben: Man schiebt \real{} ein, etwa \widthof{Total:} * \real{0.5}.
| Schreibweise | Voraussetzung | Gemessenes Ergebnis unter TeX Live 2024 |
|---|---|---|
\dimexpr | nichts (e-TeX-Primitiv) | \the\dimexpr\textwidth/3\relax ergibt 115.0pt |
\numexpr | nichts (e-TeX-Primitiv) | 7/2 ergibt 4, -7/2 ergibt -4 – Rundung, kein Abschneiden |
calc | \usepackage{calc} | (\textwidth - 2em)/2 ergibt 162.49998pt |
\real | \usepackage{calc} | \widthof{Total:} * \real{0.5} ergibt 12.91669pt |
\fpeval | der LaTeX-Kernel (xfp nicht nötig) | \fpeval{345/7}pt ergibt 49.28572pt; \fpeval{sqrt(2)} ergibt 1.414213562373095 |
Wer weiß, was die Einheiten wirklich sind, vermeidet Unfälle beim Rechnen. TeXs Bezugsgröße ist pt, der TeX-Punkt, mit 1in = 72,27pt. \the\dimexpr 1in\relax antwortet 72.26999pt – nicht exakt 72,27, weil TeX jede Dimension als ganzzahliges Vielfaches von sp, dem skalierten Punkt, hält, mit 1pt = 65536sp; \the\dimexpr 65536sp\relax ist genau 1.0pt. Der PostScript-nahe bp beträgt 1/72 in, also ist 1bp gleich 1.00374pt und 72bp kehrt zu 72.26999pt zurück, exakt 1in. Und noch etwas: em wird im Moment der Zuweisung ausgewertet und danach eingefroren. Ein \setlength{\x}{1em} in der Präambel legt 10.00002pt ab; tritt man später in eine \Large-Gruppe, steht \x weiterhin auf 10.00002pt, während ein frisch gemessenes 1em an derselben Stelle 14.09984pt ergibt. Der Einheitenkatalog selbst sowie \hspace/\vspace gehören zur Seite über Längen und Abstände.
Gesetztes ausmessen: \settowidth, \settoheight, \settodepth
Die mächtigste Längenoperation besteht darin, etwas zu setzen, das Ergebnis zu messen und in einer Länge abzulegen. \settowidth{\mylen}{text} setzt den angegebenen Text intern und weist dessen Breite an \mylen zu. Ebenso misst \settoheight die Höhe über der Grundlinie und \settodepth die Tiefe darunter. Gemessene Werte machen den Unterschied anschaulich: Total: ist 25.83339pt breit, 6.94444pt hoch und 0.0pt tief; xyz ist 4.30554pt hoch (die x-Höhe) und 1.94444pt tief; gjpqy ist 6.67859pt hoch und 1.94444pt tief. Man sieht die Tiefe genau in dem Moment entstehen, in dem eine Unterlänge in den Text tritt.
\usepackage{calc}
\newlength{\labelw}
\settowidth{\labelw}{Total:} % 25.83339pt -- the real typeset width
\noindent\makebox[\labelw][l]{Total:}42\par
\rule{\labelw}{0.4pt} % a rule exactly as wide as the label
% the same idea as a value inside an expression (needs calc):
\setlength{\labelw}{\widthof{Total:} + 1em}
\the\labelw % print the value to check itMit geladenem calc steht dieselbe Idee in Ausdrücken zur Verfügung: \widthof{text}, \heightof und \depthof lassen sich unmittelbar als Werte schreiben. Der Unterschied liegt in der Rolle: \settowidth ist ein Befehl, der das Ergebnis einer Länge zuweist, \widthof dagegen ein Wert, den man in einen Ausdruck einsetzt. Und man merke sich das Symptom, wenn calc vergessen wurde: \setlength{\mylen}{\textwidth/3} löst nicht einen einzigen Fehler aus. \mylen erhält schlicht den Wert von \textwidth (345.0pt in einem voreingestellten article), und das übrige /3 wird als Text ins Dokument gesetzt. Man bemerkt es erst, wenn „/3“ im PDF auftaucht – wer dividieren will, lädt also calc oder greift zu \dimexpr, das gar kein Paket braucht.
Alles zusammen: eine eigene, referenzierbare Aufgabennummer
Zum Schluss alle Bausteine an einem Ort. Einen Zähler question anlegen, seine gedruckte Form über \thequestion als „Q1.“ festlegen, die Beschriftungsbreite mit \settowidth messen, damit die Nummern fluchten, und den Zähler mit \refstepcounter erhöhen, damit \label und \ref funktionieren – mit diesen vier Punkten entsteht ein nummeriertes Konstrukt, das dem echten Einsatz standhält. Da das Format an genau einer Stelle sitzt, in der Definition von \thequestion, ist ein späteres Umstellen von „Q“ auf etwas anderes eine Einzeilenänderung.
\documentclass{article}
\newcounter{question}
\newlength{\qlabel}
\renewcommand{\thequestion}{Q\arabic{question}}
\newcommand{\question}{%
\refstepcounter{question}% <- \refstepcounter, so \label works
\settowidth{\qlabel}{\textbf{\thequestion.}}%
\par\noindent\makebox[\qlabel][l]{\textbf{\thequestion.}}\hspace{0.5em}}
\begin{document}
\question The first question.\label{q:first}
\question The second question.
See question~\ref{q:first}. % -> "See question Q1."
\end{document}Dieses kleine Beispiel verdichtet den Kniff, Zähler und Längen als Programmierwerkzeuge zu nutzen: Werte nicht direkt hinschreiben, sondern benennen und an einer Stelle verwalten. Zahlenformate gehören in \the…, Maße in einen mit \newlength benannten Namen; ändert sich die Vorgabe, bearbeitet man genau eine Stelle. Maße möglichst aus vorhandenen Längen aufbauen – 0.8\textwidth oder 2\baselineskip überstehen einen Wechsel von Papierformat oder Rändern. Schreibt man stattdessen 8cm fest, ist der Wert von diesem Moment an dafür vorgemerkt, bei der nächsten Layoutänderung zu brechen.