W dawnych czasach (przed ANSI) predefiniowanie symboli, takich jak unix
i vax
było sposobem, aby umożliwić kodowi wykrycie w czasie kompilacji, dla jakiego systemu był kompilowany. Nie było wówczas oficjalnego standardu językowego (poza materiałem referencyjnym na końcu pierwszej edycji K&R), a kod C o dowolnej złożoności był zwykle złożonym labiryntem #ifdef
s, aby uwzględnić różnice między systemami. Te definicje makr zostały na ogół ustawione przez sam kompilator, a nie zdefiniowane w pliku nagłówkowym biblioteki. Ponieważ nie istniały żadne rzeczywiste reguły określające, które identyfikatory mogłyby być używane przez implementację i które były zarezerwowane dla programistów, autorzy kompilatorów mogli swobodnie używać prostych nazw podobnych unix
i zakładali, że programiści po prostu unikaliby używania tych nazw do własnych celów.
Norma ANSI C z 1989 r. Wprowadziła zasady ograniczające, które symbole implementacja mogłaby z góry zdefiniować. Makro predefiniowane przez kompilator może mieć nazwę zaczynającą się od dwóch znaków podkreślenia lub znaku podkreślenia, po którym następuje wielka litera, pozostawiając programistom swobodę używania identyfikatorów niepasujących do tego wzorca i nieużywanych w bibliotece standardowej.
W rezultacie każdy kompilator, który predefiniuje unix
lub linux
jest niezgodny, ponieważ nie skompiluje idealnie legalnego kodu, który używa czegoś takiego int linux = 5;
.
Tak się składa, że gcc jest domyślnie niezgodny - ale można go dostosować (dość dobrze) za pomocą odpowiednich opcji wiersza poleceń:
gcc -std=c90 -pedantic ... # or -std=c89 or -ansi
gcc -std=c99 -pedantic
gcc -std=c11 -pedantic
Więcej informacji znajduje się w instrukcji gcc .
gcc będzie wycofywał te definicje w przyszłych wydaniach, więc nie powinieneś pisać kodu, który zależy od nich. Jeśli twój program musi wiedzieć, czy jest kompilowany dla systemu Linux, może sprawdzić, czy __linux__
jest zdefiniowany (zakładając, że używasz gcc lub kompilatora, który jest z nim kompatybilny). Zobacz instrukcję preprocesora GNU C , aby uzyskać więcej informacji.
Pomijając kwestię w dużej mierze nieistotną: zwycięzca Międzynarodowego Konkursu Obfuscated C Code w 1987 r. „Best One Liner” autorstwa Davida Korna (tak, autor Korn Shell) skorzystał ze wstępnie zdefiniowanego unix
makra:
main() { printf(&unix["\021%six\012\0"],(unix)["have"]+"fun"-0x60);}
Drukuje "unix"
, ale z powodów, które absolutnie nie mają nic wspólnego z pisownią nazwy makra.