Dies scheint eine (undokumentierte) "GNU-Erweiterung" zu sein:[Korrektur :Ich habe endlich eine Erwähnung in den Dokumenten gefunden. Siehe unten.]
Der folgende Befehl verwendet den -dM
Option zum Drucken aller Präprozessordefinitionen; Da die Eingabe "Datei" leer ist, zeigt sie genau die vordefinierten Makros. Es wurde mit gcc-4.7.3 auf einer Standard-Ubuntu-Installation ausgeführt. Sie können sehen, dass der Präprozessor standardbewusst ist. Insgesamt gibt es 243 Makros mit -std=gnu99
und 240 mit -std=c99
; Ich habe die Ausgabe nach Relevanz gefiltert.
$ cpp --std=c89 -dM < /dev/null | grep linux
#define __linux 1
#define __linux__ 1
#define __gnu_linux__ 1
$ cpp --std=gnu89 -dM < /dev/null | grep linux
#define __linux 1
#define __linux__ 1
#define __gnu_linux__ 1
#define linux 1
$ cpp --std=c99 -dM < /dev/null | grep linux
#define __linux 1
#define __linux__ 1
#define __gnu_linux__ 1
$ cpp --std=gnu99 -dM < /dev/null | grep linux
#define __linux 1
#define __linux__ 1
#define __gnu_linux__ 1
#define linux 1
Die "GNU-Standard"-Versionen auch #define unix
. (Mit c11
und gnu11
erzeugt die gleichen Ergebnisse.)
Ich nehme an, sie hatten ihre Gründe, aber es scheint mir, dass die Standardinstallation von gcc (die C-Code mit -std=gnu89
kompiliert sofern nicht anders angegeben) nicht konform und – wie in dieser Frage – überraschend. Das Verschmutzen des globalen Namensraums mit Makros, deren Namen nicht mit einem Unterstrich beginnen, ist in einer konformen Implementierung nicht erlaubt. (6.8.10p2:„Alle anderen vordefinierten Makronamen müssen mit einem führenden Unterstrich beginnen, gefolgt von einem Großbuchstaben oder einem zweiten Unterstrich“, aber wie in Anhang J.5 (Portabilitätsprobleme) erwähnt, sind solche Namen oft vordefiniert.)
Als ich diese Antwort ursprünglich schrieb, konnte ich in gcc keine Dokumentation zu diesem Problem finden, aber ich habe es schließlich entdeckt, weder im durch die C-Implementierung definierten Verhalten noch in C-Erweiterungen, sondern im cpp
Abschnitt 3.7.3 des Handbuchs, wo Folgendes vermerkt ist:
Wir stellen alle vordefinierten Makros, die außerhalb des reservierten Namensraums liegen, langsam aus. Sie sollten sie niemals in neuen Programmen verwenden…
Früher (vor ANSI) wurden Symbole wie unix
vordefiniert und vax
war eine Möglichkeit, Code zur Kompilierzeit zu erkennen, für welches System er kompiliert wurde. Damals gab es keinen offiziellen Sprachstandard (außer dem Referenzmaterial am Ende der ersten Ausgabe von K&R), und C-Code jeglicher Komplexität war typischerweise ein komplexes Labyrinth von #ifdef
s um Unterschiede zwischen Systemen zu berücksichtigen. Diese Makrodefinitionen wurden im Allgemeinen vom Compiler selbst festgelegt und nicht in einer Bibliotheksheaderdatei definiert. Da es keine wirklichen Regeln darüber gab, welche Bezeichner von der Implementierung verwendet werden konnten und welche Programmierern vorbehalten waren, fühlten sich Compiler-Autoren frei, einfache Namen wie unix
zu verwenden und davon ausgegangen, dass Programmierer es einfach vermeiden würden, diese Namen für ihre eigenen Zwecke zu verwenden.
Der ANSI C-Standard von 1989 führte Regeln ein, die einschränken, welche Symbole eine Implementierung legal vordefinieren kann. Ein vom Compiler vordefiniertes Makro konnte nur einen Namen haben, der mit zwei Unterstrichen oder einem Unterstrich gefolgt von einem Großbuchstaben beginnt, was Programmierern die Möglichkeit gibt, Bezeichner zu verwenden, die nicht diesem Muster entsprechen und nicht in der Standardbibliothek verwendet werden.
Als Ergebnis wird jeder Compiler, der unix
vordefiniert oder linux
ist nicht konform, da es nicht vollständig legalen Code kompilieren kann, der so etwas wie int linux = 5;
verwendet .
Zufälligerweise ist gcc standardmäßig nicht konform – aber es kann (ziemlich gut) mit den richtigen Befehlszeilenoptionen konform gemacht werden:
gcc -std=c90 -pedantic ... # or -std=c89 or -ansi
gcc -std=c99 -pedantic
gcc -std=c11 -pedantic
Weitere Einzelheiten finden Sie im gcc-Handbuch.
gcc wird diese Definitionen in zukünftigen Versionen auslaufen lassen, daher sollten Sie keinen Code schreiben, der von ihnen abhängt. Wenn Ihr Programm wissen muss, ob es für ein Linux-Ziel kompiliert wird oder nicht, kann es prüfen, ob __linux__
definiert ist (vorausgesetzt, Sie verwenden gcc oder einen damit kompatiblen Compiler). Weitere Informationen finden Sie im GNU C-Präprozessor-Handbuch.
Eine weitgehend irrelevante Randbemerkung:Der Gewinner des „Best One Liner“ des International Obfuscated C Code Contest von 1987 von David Korn (ja, der Autor der Korn Shell) nutzte den vordefinierten unix
Makro:
main() { printf(&unix["\021%six\012\0"],(unix)["have"]+"fun"-0x60);}
Es gibt "unix"
aus , aber aus Gründen, die absolut nichts mit der Schreibweise des Makronamens zu tun haben.