In den alten Tagen (vor ANSI) war das Vordefinieren von Symbolen wie unix
und vax
eine Möglichkeit, dem Code zu ermöglichen, zur Kompilierzeit zu erkennen, für welches System er kompiliert wurde. Damals gab es keinen offiziellen Sprachstandard (außer den Referenzmaterialien am Ende der ersten Ausgabe von K&R, 1978) und C-Code jeder Komplexität war typischerweise ein komplexes Labyrinth von #ifdef
s, um Unterschiede zwischen Systemen zu ermöglichen. Diese Makrodefinitionen wurden im Allgemeinen vom Compiler selbst festgelegt, nicht in einer Bibliothekskopfdatei definiert. Da es damals keine echten Regeln dafür gab, welche Bezeichner von der Implementierung verwendet werden konnten und welche für Programmierer reserviert waren, fühlten sich Compiler-Entwickler frei, einfache Namen wie unix
zu verwenden und gingen davon aus, dass Programmierer einfach solche Namen für ihre eigenen Zwecke nicht verwenden würden.
Der ANSI-C-Standard von 1989 führte Regeln ein, die beschränkten, welche Symbole eine Implementierung legal vordefinieren konnte. Ein vom Compiler vordefiniertes Makro konnte nur einen Namen haben, der mit zwei Unterstrichen beginnt oder mit einem Unterstrich gefolgt von einem Großbuchstaben, und ließ Programmierer frei, Bezeichner zu verwenden, die nicht diesem Muster entsprechen und nicht in der Standardbibliothek verwendet werden.
Als Folge davon ist jeder Compiler, der unix
oder linux
vordefiniert, nicht konform, da er nicht in der Lage sein wird, völlig legalen Code zu kompilieren, der etwas wie int linux = 5;
verwendet.
Wie es scheint, ist gcc standardmäßig nicht konform - aber es kann durch die richtigen Befehlszeilenoptionen (vernünftig gut) konform gemacht werden:
gcc -std=c90 -pedantic ... # oder -std=c89 oder -ansi
gcc -std=c99 -pedantic
gcc -std=c11 -pedantic
Wenn du das hier liest, wird gcc wahrscheinlich neuere Ausgaben des C-Standards unterstützen. Siehe das gcc-Handbuch für weitere Details.
gcc könnte diese Definitionen (unix
, linux
, usw.) in zukünftigen Versionen auslaufen lassen, daher solltest du keinen Code schreiben, der von ihnen abhängt. Wenn dein Programm wissen muss, ob es für ein Linux-Ziel kompiliert wird oder nicht, kann es überprüfen, ob __linux__
definiert ist (vorausgesetzt, du verwendest gcc oder einen kompatiblen Compiler). Siehe das GNU C Vorkompilierer-Handbuch für weitere Informationen.
Eine ziemlich irrelevante Randnotiz: Der "Best One Liner"-Gewinner des International Obfuscated C Code Contest von 1987, von David Korn (ja, dem Autor der Korn-Shell), nutzte das vordefinierte unix
-Makro:
main() { printf(&unix["\021%six\012\0"],(unix)["have"]+"fun"-0x60);}
Es druckt "unix"
, aber aus Gründen, die absolut nichts mit der Schreibweise des Makronamens zu tun haben.
Ich möchte hier keine Spoiler posten und ermutige jeden, der dies liest, zuerst zu versuchen, diesen Code selbst zu verstehen. Aber wenn du wirklich aufgeben willst, habe ich hier eine Erklärung gepostet: https://gist.github.com/Keith-S-Thompson/6920347