Nach \if
expandiert TeX so lange, bis zwei nicht expandierbare Tokens gefunden werden. Ist das nicht expandierbare Token eine Kontrollsequenz, also beispielsweise ein TeX Primitiv, so wird diesem der Code 256 zugeordnet. Ansonsten wird der Zeichencode des Tokens (kann bei TeX zwischen 0 und 255 liegen, da TeX nur 8-Bit-Zeichen verarbeitet) genommen. Diese beiden Codes werden dann verglichen.
Beispiele:
\if\noexpand\end\relax ja\else nein\fi
Ergibt: ja
, weil \noexpand\end
zu einem nicht expandierbaren \end
expandiert und diesem als Kontrollsequenz dann 256 zugeordnet wird und \relax
nicht expandierbar ist und direkt 256 zugeordnet bekommt.
Ergibt: nein
, weil a
und b
nicht expandierbare Tokens sind und der Zeichencode von a
und b
nicht gleich ist.
\def\a{a}\if a\a ja\else nein\fi
Ergibt: ja
, weil das erste a
nicht expandierbar ist, \a
ebenfalls zu a
expandiert und dann die beiden a
den gleichen Zeichencode haben.
\def\a{a}\if \a aja\else nein\fi
Ergibt: ja
, weil \a
zu a
expandiert und dann die beiden a
den gleichen Zeichencode haben.
\def\a{ab}\def\b{ab}\if \a\b ja\else nein\fi
Ergibt: nein
, weil \a
zu ab
expandiert, das zwei nicht expandierbare Tokens sind, a
und b
unterschiedlichen Zeichencode haben und damit der \else
-Teil ausgeführt wird.
\def\a{aa}\def\b{bb}\if \a\b ja\else nein\fi
Ergibt: bbja
, weil \a
zu aa
expandiert, das zwei nicht expandierbare Tokens sind, a
und a
denselben Zeichencode haben und dann \b ja
vor dem \else
übrig bleiben.
\def\a{aa}\def\b{bb}\ifx \a\b ja\else nein\fi
Ergibt: nein
, weil \ifx
anders als \if
funktioniert.
Als weiterführende Literatur empfehle ich hierzu »TeX by Topic« (Kapitel 13) oder »The TeXbook«.
Im LaTeX-Kern wird \if
beispielsweise verwendet, um zeichenweise die Ein-Zeichen-Optionen für die Gleitumgebungsoptionen mit einzelnen Buchstaben zu vergleichen oder die einzelnen Zeichen einer kleinen, römischen Zahl in Großbuchstaben für eine große, römische Zahl zu wandeln oder die Platzierungs-Optionen von \makebox
, \parbox
, minipage
oder tabular
zeichenweise mit entsprechenden Buchstaben zu vergleichen.
\@ifundefined
und \@ifpackageloaded
sind übrigens nicht mit \if
, \ifx
oder \ifodd
zu vergleichen, da sie eine ganz andere Syntax haben. Die \if… … \else … \fi
-Syntax ist für diese nicht verwendbar, da TeX bei dieser Syntax eine Abkürzung nimmt, sobald es weiß, ob die Bedingung zutrifft oder nicht. Es wird nämlich je nachdem der true-Teil oder der else-Teil einfach übersprungen, wobei nicht mehr expandiert wird, sondern lediglich Ebenen von \iftrue … \else … \fi
und \iffalse … \else … \fi
mit berücksichtigt werden. Deshalb darf man auf keinen Fall eine Definition wie:
\def\@ifundefined#1{\expandafter\ifx\csname #1\endcsname\relax}
verwenden. Diese würde beispielsweise in
\iffalse
\def\test{ok}%
\@ifundefined\test ok\fi
\else
not ok
\fi
Zu einem Extra \else
-Fehler führen, weil \@ifundefined\test
nicht expandiert würde und damit das erste \fi
bereits das Ende von \iffalse
wäre. Aus genau diesem Grund, ist \@ifundefined
im LaTeX-Kern stattdessen eine Anweisung mit drei Argumenten (wobei die letzten beiden von \@firstoftwo
oder \@secondoftwo
gelesen werden). Ich erwähne das, weil Anfänger gerne solche Fehler machen.
\if<token1><token2>
testet beide Token in Bezug auf den Character-Code. Die Token werden dabei expandiert, wenn es sich um Makros handelt. Ich verwende es v.a. um auf leere Argumente zu testen:\if\relax\detokenize{#1}\relax
: wenn#1
leer ist, wird\relax
mit\relax
verglichen, die Abfrage ist wahr. Enthält#1
irgendwas (selbst\relax
), dann ist die Abfrage falsch, weil\detokenize
eine Reihe von Charaktern mit Kategorie-Code 12 zurücklässt (was aus\relax
sechs Charaktere machen würde).@Clemens: Das Leerzeichen (Zeichencode 32) ist bei
\detokenize
übrigens ein Space-Tokens, bekommt also als Ausnahme Kategorie-Code 10, was natürlich für Dein Beispiel keine Rolle spielt, weil ein Leerzeichen ja nicht nichts ist, auch wenn manche Anwender das anders sehen.@saputello Ich weiß, ich hatte nur das Gefühl, dass mein Kommentar schon zu lang würde, deshalb hab ich das einfach unterschlagen ;)
@Clemens Gut zu wissen, dass man auch mit
\if
testen kann, ob ein Argument leer ist. Bisher kannte ich nur\ifx\\#1\\
.