\setcounter and \setlength look alike and behave in opposite ways. Run both inside a group and, once the group closes, the counter keeps its new value while the length silently reverts — because one of the two carries the word \global in its kernel definition and the other does not. This page is about LaTeX’s two numeric registers: counters (\newcounter), which hold an integer and drive every chapter, figure and equation number, and lengths (\newlength), which hold a dimension and turn out to be glue registers rather than plain dimensions. Along the way: why a \label placed after \stepcounter quietly references somebody else’s number, what \value actually expands to, and how to compute with \dimexpr, calc and \fpeval — conversions such as 1in = 72.27pt and 1pt = 65536sp included.
Creating and moving a counter with \newcounter
A new counter comes from \newcounter{foo}. The name is a plain string with no backslash, and the value right after creation is 0. Underneath it is a TeX \count register — ask \meaning and it answers something like \count196. Three commands change the value: \setcounter{foo}{3} assigns, \addtocounter{foo}{2} adds (a negative number subtracts), and \stepcounter{foo} adds exactly 1. The optional second argument, \newcounter{foo}[⟨parent⟩], makes foo subordinate to parent, so that every time parent is stepped, foo drops back to 0. That is precisely the mechanism behind subsection numbers restarting when the section changes.
\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.The exact wording of the errors is worth remembering. Touch a counter that does not exist and you get ! LaTeX Error: No counter 'nosuch' defined.; run \newcounter twice on the same name and you get ! LaTeX Error: Command \c@trial already defined. That \c@trial it names is the internal register actually holding trial — and since the name contains @, reaching it from a preamble needs \makeatletter. Resetting is handled by an internal macro, \@stpelt, whose body sets the child to −1 and then calls \stepcounter on it. Stepping rather than simply assigning 0 is what makes the reset cascade all the way down to grandchild counters.
\stepcounter vs \refstepcounter: when \label points at somebody else’s number
\refstepcounter{foo} performs the same stepping and resetting as \stepcounter, and then makes foo the number that can currently be referenced. Without that extra move, \label has nothing to hold on to. Measured, the symptom is nastier than you would guess. In a document with three sections, \stepcounter{demo}\label{bad} leaves demo at 1 — yet what lands in the .aux file is \newlabel{bad}{{3}{1}{}{}{}}, so \ref{bad} prints 3, the number of the preceding section. The label does not fall back to the counter’s previous value; it latches onto whichever counter \refstepcounter touched last, which is usually an entirely different one. And there is no error and no warning. Do the same at the very top of a document and you get \newlabel{step}{{}{1}{}{}{}}, with \ref printing nothing at all.
\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 = 1The mechanism is plain in latex.ltx. \refstepcounter calls \stepcounter and then writes the value of \thefoo into \@currentlabel; \label does nothing but copy \@currentlabel into the .aux file. So \label never stores “the counter just before me” — it stores the current value of a global variable. LaTeX itself uses \refstepcounter when it steps section, equation or figure, which is why a \label on a heading or an equation gives the right number. The practical rule follows immediately: use \stepcounter when you only need a number to advance internally, and \refstepcounter when you are creating a numbered thing that \label should be able to reference. When a home-made theorem environment or exercise number refuses to cross-reference correctly, look here first.
\value: getting a counter out as a number you can compute with
\value{foo} expands to the very \count register that holds the counter — the kernel definition is literally the one line \csname c@#1\endcsname. That is why it works in the value slot of \setcounter and \addtocounter, in an \ifnum comparison, inside a \numexpr expression — anywhere LaTeX expects an integer. Turn it around and the corollary is that \value is not a printing command. Putting a number into the text is the job of \arabic or \thefoo in the next section; \value only ever hands back the raw number for arithmetic. Keep the two roles apart and the “my number does not appear” and “the digit came out twice” confusions stop happening.
\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 definedChanging how a number looks: from \arabic to \thefoo
Six commands turn a counter’s value into printed characters, and each takes a counter name as its argument. But the number you actually see is emitted by \thefoo, a dedicated macro every counter gets automatically: section has \thesection, figure has \thefigure, and redefining that with \renewcommand changes the whole number format at a stroke. \alph and \Alph map onto the 26 letters. The boundary is finer than it looks: 0 prints nothing at all and raises no error, while negatives and anything above 26 give ! LaTeX Error: Counter too large. \fnsymbol also has a valid range of 1–9, and 10 raises the same ! LaTeX Error: Counter too large. One correction to older advice while we are here: in the LaTeX2e shipped with TeX Live 2024, \@fnsymbol is defined with \TextOrMath in every case, so \fnsymbol works directly in running text — the $\fnsymbol{footnote}$ wrapper is no longer needed (for footnotes, \thefootnote remains the usual route).
| Command | Output | Range / caveats |
|---|---|---|
\arabic | 1, 2, 3 … | The default; negative values print too |
\roman | i, ii, iii … | Below 1 prints nothing |
\Roman | I, II, III … | Below 1 prints nothing |
\alph | a, b, c … | 1–26. 0 prints nothing; negatives and 27+ give Counter too large |
\Alph | A, B, C … | 1–26. 0 prints nothing; negatives and 27+ give Counter too large |
\fnsymbol | ∗ † ‡ § ¶ ‖ ∗∗ †† ‡‡ | 1–9; 10 gives Counter too large. Works in plain text; no math wrapper needed |
\thefoo | The counter’s official format | This is what actually prints; change it with \renewcommand |
\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}}As in the second example, weaving another counter’s display into a \the… definition produces compound numbers like “2.3”. What that reveals is the design: the appearance of a number (the definition of \thefigure) and the linkage that decides when it resets (the parent argument of \newcounter) are settled entirely independently. So writing \renewcommand{\thefigure}{\thesection.\arabic{figure}} on its own does not make figure numbers restart at each section — for that you also have to set up the parent relationship, for instance with \counterwithin{figure}{section}.
The standard counters, and secnumdepth / tocdepth as configuration values
LaTeX predefines a family of counters and drives them automatically as it reads through the document. You can touch these with \setcounter too, which is how one renumbers chapters partway through or makes appendix figures read A.1. Create a single counter in an empty article and its internal register lands around \count196 — meaning several dozen standard counters are already running. Classic TeX allowed only 256 registers of each kind; e-TeX raised that ceiling, so allocating 400 counters in a row now draws no complaint at all (the last one landed on \count662).
- Sectioning:
part,chapter,section,subsection,subsubsection,paragraph,subparagraph(which exist depends on the class) - Floats and equations:
figure,table,equation - Footnotes:
footnote,mpfootnote(footnotes inside aminipage) - Lists:
enumi,enumii,enumiii,enumiv(the four nesting levels ofenumerate) - Page:
page - Configuration values:
secnumdepth(how deep sectioning is numbered) andtocdepth(how deep entries reach the table of contents)
The last two are a different animal: integer dials that govern how “deep” numbering and the table of contents go, not tallies of anything. Each sectioning command has a level number (section is 1, subsection is 2, …) and a level is numbered only when that number is less than or equal to secnumdepth. The default is around 2, so \setcounter{secnumdepth}{1} removes the numbers below section level, and \setcounter{tocdepth}{1} trims the table of contents to sections. These two make the point neatly: a counter is not only a tally but also a configuration value that steers the typesetting.
\newlength allocates a skip register, not a dimen
\newlength{\mylen} is \newskip underneath. The kernel definition is the single line \@ifdefinable#1{\newskip#1}, and \meaning confirms it by answering something like \skip50. That matters, because a skip register can carry stretch and shrink, which is why \setlength{\parskip}{1em plus 2pt minus 1pt} is a perfectly legal assignment. Measured, \the\parskip then reports 10.00002pt plus 2.0pt minus 1.0pt — all three components preserved. Unlike a counter, the argument is a command name with a backslash (\mylen), and the initial value is 0pt. Declaring the same name twice gives ! LaTeX Error: Command \mylen already defined. And since \a, \b, \c, \d and \t already exist as accent commands, that is exactly why \newlength{\a} will not go through.
\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" used\showbox lets you read the stretching and shrinking straight out of the log. Force a box of natural width 60pt to 70pt and you get glue set 1.0 — meaning the whole plus 10pt was consumed. Squeeze it to 55pt and you get glue set - 1.0, all of the minus 5pt used up. That glue set figure is a strong ally when investigating layout: a value of 2 or 3 tells you the box is being stretched well past comfort. How plus and minus behave across a whole page — the story of \fill and \flushbottom — is covered in detail on the lengths-and-spacing page.
Why \setcounter is global and \setlength is local
The reason is a single word in the latex.ltx definitions. \setcounter and \addtocounter carry \global; \setlength and \addtolength do not. That one difference produces entirely different behaviour. Change a counter and a length inside the same group and, once the group closes, the counter keeps its new value while the length is back to its old one — measured, a length taken from 1cm to 9cm snapped back to 28.45274pt (that is, 1cm) the moment the group ended. The asymmetry makes sense: a chapter number is document state that must not be forgotten when an environment ends, whereas a temporary tweak to a margin is meant to apply only within its own stretch.
\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}This difference starts to matter as soon as you write your own tools with \newcommand or \newenvironment. Write \setlength{\parindent}{0pt} inside an environment and it reverts automatically at \end — no cleanup needed. Conversely, if a count made inside an environment has to survive outside it, you need \setcounter (or an explicit \global). The two classic bugs — “my setting vanished when the environment ended” and “my margin change leaked outside the environment” — are both explained by the presence or absence of that one word. The fact that an environment forms a group in the first place is covered on the page about writing environments.
Computing with lengths: \dimexpr, calc, \fpeval, and the unit conversions
Of addition, multiplication and division, the ones you can write with no package at all are the e-TeX primitives \numexpr and \dimexpr. In a default article, \the\dimexpr\textwidth/3\relax returns 115.0pt, and \the\dimexpr 2cm+4pt\relax gives 60.9055pt. One caveat: division in \numexpr rounds, it does not truncate — \the\numexpr 7/2\relax is 4 and -7/2 is −4. For a more LaTeX-flavoured syntax, load the calc package, which lets an expression like \setlength{\x}{(\textwidth - 2em)/2} sit directly inside \setlength (measured: 162.49998pt). Scaling by a real factor is the one case written differently: you interpose \real{}, as in \widthof{Total:} * \real{0.5}.
| Written as | What it needs | Measured result under TeX Live 2024 |
|---|---|---|
\dimexpr | nothing (an e-TeX primitive) | \the\dimexpr\textwidth/3\relax gives 115.0pt |
\numexpr | nothing (an e-TeX primitive) | 7/2 gives 4, -7/2 gives -4 — rounding, not truncation |
calc | \usepackage{calc} | (\textwidth - 2em)/2 gives 162.49998pt |
\real | \usepackage{calc} | \widthof{Total:} * \real{0.5} gives 12.91669pt |
\fpeval | the LaTeX kernel (xfp not needed) | \fpeval{345/7}pt gives 49.28572pt; \fpeval{sqrt(2)} gives 1.414213562373095 |
Knowing what the units really are prevents accidents when you compute. TeX’s reference is pt, the TeX point, with 1in = 72.27pt. \the\dimexpr 1in\relax answers 72.26999pt — not exactly 72.27 because TeX keeps every dimension as a whole number of sp, the scaled point, with 1pt = 65536sp; \the\dimexpr 65536sp\relax is exactly 1.0pt. The PostScript-family bp is 1/72 in, so 1bp is 1.00374pt and 72bp comes back to 72.26999pt, precisely 1in. One more thing: em is evaluated at the moment of assignment and then frozen. Write \setlength{\x}{1em} in the preamble and 10.00002pt goes in; step later into a \Large group and \x is still 10.00002pt, while a fresh 1em measured in the same place is 14.09984pt. The unit catalogue itself, and \hspace/\vspace, belong to the lengths-and-spacing page.
Measuring what you typeset: \settowidth, \settoheight, \settodepth
The most powerful length operation is to typeset something, measure the result, and store it in a length. \settowidth{\mylen}{text} sets the given text internally and assigns its width to \mylen. In the same way \settoheight measures the height above the baseline and \settodepth the depth below it. Measured values make the distinction vivid: Total: comes out 25.83339pt wide, 6.94444pt high and 0.0pt deep; xyz is 4.30554pt high (the x-height) and 1.94444pt deep; gjpqy is 6.67859pt high and 1.94444pt deep. You can watch the depth appear the moment a descender enters the text.
\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 itLoad calc and the same idea becomes available inside expressions, with \widthof{text}, \heightof and \depthof usable directly as values. The difference is one of role: \settowidth is a command that assigns the result to a length, while \widthof is a value you can drop into an expression. And remember the symptom of forgetting to load calc: \setlength{\mylen}{\textwidth/3} raises not a single error. \mylen simply receives the value of \textwidth (345.0pt in a default article) and the leftover /3 is typeset into the document as text. You find out when “/3” shows up in the PDF — so if you are going to divide, either load calc or use \dimexpr, which needs no package at all.
Putting it together: a referenceable exercise number of your own
Finally, here are all the parts in one place. Create a counter question, fix its printed form as “Q1.” by defining \thequestion, measure the label width with \settowidth so the numbers align, and step the counter with \refstepcounter so that \label and \ref work — with those four in place, you have a numbered construct fit for real use. Because the format lives in exactly one spot, the definition of \thequestion, changing “Q” to something else later is a one-line edit.
\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}That small example concentrates the knack of using counters and lengths as programming tools: do not write values inline; give them names and manage them in one place. Keep number formats in \the… and dimensions in a \newlength name, and when the specification changes you edit one spot. Build dimensions out of existing lengths wherever you can — write 0.8\textwidth or 2\baselineskip and the proportion survives a change of paper size or margins. Hard-code 8cm instead, and from that moment the value is booked to break at the next layout change.