Dans l'ancien temps (pré-ANSI), prédéfinir des symboles tels que unix
et vax
était un moyen de permettre au code de détecter au moment de la compilation pour quel système il était compilé. Il n'y avait pas de norme de langue officielle à l'époque (au-delà du matériel de référence à la fin de la première édition de K&R), et le code C de toute complexité était généralement un labyrinthe complexe de #ifdef
s pour permettre les différences entre les systèmes. Ces définitions de macro ont généralement été définies par le compilateur lui-même, non définies dans un fichier d'en-tête de bibliothèque. Comme il n'y avait pas de règles réelles sur les identifiants qui pouvaient être utilisés par l'implémentation et ceux qui étaient réservés aux programmeurs, les rédacteurs du compilateur se sentaient libres d'utiliser des noms simples comme unix
et supposaient que les programmeurs éviteraient simplement d'utiliser ces noms à leurs propres fins.
La norme ANSI C de 1989 a introduit des règles limitant les symboles qu'une mise en œuvre pourrait légalement prédéfinir. Une macro prédéfinie par le compilateur ne peut avoir qu'un nom commençant par deux traits de soulignement, ou avec un trait de soulignement suivi d'une lettre majuscule, laissant les programmeurs libres d'utiliser des identificateurs ne correspondant pas à ce modèle et non utilisés dans la bibliothèque standard.
En conséquence, tout compilateur qui prédéfinit unix
ou linux
n'est pas conforme, car il ne parviendra pas à compiler un code parfaitement légal qui utilise quelque chose comme int linux = 5;
.
En l'occurrence, gcc n'est pas conforme par défaut - mais il peut être rendu conforme (raisonnablement bien) avec les bonnes options de ligne de commande:
gcc -std=c90 -pedantic ... # or -std=c89 or -ansi
gcc -std=c99 -pedantic
gcc -std=c11 -pedantic
Voir le manuel de gcc pour plus de détails.
gcc supprimera progressivement ces définitions dans les versions futures, vous ne devez donc pas écrire de code qui en dépend. Si votre programme a besoin de savoir s'il est compilé pour une cible Linux ou non, il peut vérifier s'il __linux__
est défini (en supposant que vous utilisez gcc ou un compilateur compatible avec lui). Voir le manuel du préprocesseur GNU C pour plus d'informations.
Un côté largement hors de propos: le "Best One Liner" vainqueur du Concours International de Code C Obfuscated 1987 , par David Korn (oui, l'auteur du Korn Shell) a profité de la unix
macro prédéfinie :
main() { printf(&unix["\021%six\012\0"],(unix)["have"]+"fun"-0x60);}
Il s'imprime "unix"
, mais pour des raisons qui n'ont absolument rien à voir avec l'orthographe du nom de la macro.