Pourquoi le préprocesseur C dans GCC interprète-t-il le mot linux
(petites lettres) comme la constante 1
?
test.c:
#include <stdio.h>
int main(void)
{
int linux = 5;
return 0;
}
Résultat de $ gcc -E test.c
(arrêt après la phase de prétraitement):
....
int main(void)
{
int 1 = 5;
return 0;
}
Ce qui bien sûr donne une erreur.
(BTW: Il n'y #define linux
en a pas dans le stdio.h
fichier.)
c
linux
gcc
c-preprocessor
ahmedaly50
la source
la source
#undef linux
ou peut-être utilisé une variable différente? Je pense que la constantelinux
est utilisée pour tester les systèmes d'exploitation, par exemple si vous concevez une application multiplateforme et avez besoin de savoir exactement quelle API utiliser (windows, mac, linux, BSD, etc.). Ce n'est pas dans stdio.h, mais il est toujours défini si le noyau est linux. Le même code ne devrait pas produire d'erreur dans Windows, mais utiliser quelque chose comme Windows ou WINDOWS comme la variable le fera probablement, et vice versaRéponses:
Dans l'ancien temps (pré-ANSI), prédéfinir des symboles tels que
unix
etvax
é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 commeunix
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
oulinux
n'est pas conforme, car il ne parviendra pas à compiler un code parfaitement légal qui utilise quelque chose commeint 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:
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 :Il s'imprime
"unix"
, mais pour des raisons qui n'ont absolument rien à voir avec l'orthographe du nom de la macro.la source
unix
etvax
" - Hein? C'était ma compréhension que dans les temps anciens, tout le monde était unvax
!unix
définition). J'ai expliqué pourquoi dans un commentaire sur ce point si vous, ou quelqu'un d'autre, êtes curieux.Cela semble être une "extension GNU" (non documentée): [ correction : j'ai finalement trouvé une mention dans la documentation. Voir ci-dessous.]
La commande suivante utilise l'
-dM
option pour imprimer toutes les définitions de préprocesseur; puisque le "fichier" d'entrée est vide, il affiche exactement les macros prédéfinies. Il a été exécuté avec gcc-4.7.3 sur une installation ubuntu standard. Vous pouvez voir que le préprocesseur est compatible avec les normes. Au total, il y a 243 macros avec-std=gnu99
et 240 avec-std=c99
; J'ai filtré la sortie pour la pertinence.Les versions "gnu standard" également
#define unix
. (Utilisation dec11
etgnu11
produit les mêmes résultats.)Je suppose qu'ils avaient leurs raisons, mais il me semble faire l'installation par défaut de gcc (qui compile le code C avec
-std=gnu89
sauf indication contraire) non conforme, et - comme dans cette question - surprenante. La pollution de l'espace de noms global avec des macros dont les noms ne commencent pas par un trait de soulignement n'est pas autorisée dans une implémentation conforme. (6.8.10p2: "Tout autre nom de macro prédéfini doit commencer par un trait de soulignement principal suivi d'une lettre majuscule ou d'un deuxième trait de soulignement", mais, comme mentionné à l'annexe J.5 (problèmes de portabilité), ces noms sont souvent prédéfinis.)Lorsque j'ai écrit cette réponse à l'origine, je n'ai trouvé aucune documentation dans gcc à propos de ce problème, mais je l'ai finalement découverte, pas dans le comportement défini par l'implémentation C ni dans les extensions C mais dans la
cpp
section 3.7.3 du manuel , où il note que:la source
-std=gnu89
c'est la valeur par défaut, et pour autant que je sache, c'est la valeur par défaut sur Solaris, Linux et Mac OS X ( developer.apple.com/library/mac/documentation/Darwin/Reference/… pour ce dernier), et c'est celui qui pollue l'espace de noms.c89
essaie de se conformer à la norme, donc si c'était la valeur par défaut, je ne me plaindrais pas.Parce
linux
qu'une macro intégrée est définie lorsque le compilateur s'exécute sur, ou compile pour (s'il s'agit d'un compilateur croisé), Linux.Il existe de nombreuses macros prédéfinies. Avec GCC, vous pouvez utiliser:
pour obtenir une liste des macros. (Je n'ai pas réussi à persuader GCC d'accepter
/dev/null
directement, mais le fichier vide semble fonctionner correctement.) Avec GCC 4.8.1 fonctionnant sur Mac OS X 10.8.5, j'ai obtenu la sortie:C'est 236 macros à partir d'un fichier vide. Lorsque j'ai ajouté
#include <stdio.h>
au fichier, le nombre de macros définies est passé à 505. Cela inclut toutes sortes de macros d'identification de plate-forme.la source
cpp -dM < /dev/null
linux
) n'est pas défini sur ma machine Mac OS X - il ne fonctionne pas sous Linux (enfin, il y a une VM sous Linux, mais ...). Il peut être défini par les en-têtes inclus par<stdio.h>
; exécuter un fichier vide peut ne pas être le même./dev/null
comme fichier source-x
car il n'a pas d'extension, donc gcc ne sait pas s'il s'agit de C ou C ++. Vous pouvez utilisergcc -E -dM -x c /dev/null
ougcc -E -dm -x c++ /dev/null
pour obtenir la liste sans avoir à créer un fichier vide.cpp
(le préprocesseur) nongcc
. Notez aussi que je ne donne pas/dev/null
comme un fichier d'entrée, mais je l' utilise pour faire la redirection/dev/null
enstdin
. Aussi @KerrekSB: sur ma machine Debianlinux
est sur la liste.> emptyfile.c
ou: > emptyfile.c
oudd if=/etc/passwd of=emptyfile.c count=0
ou…De
info gcc
(souligné par moi):(Il utilise vax dans l'exemple au lieu de linux car quand il a été écrit, il était peut-être plus populaire ;-).
L'idée de base est que GCC essaie de se conformer pleinement aux normes ISO uniquement lorsqu'il est invoqué avec l'
-ansi
option.la source
-ansi
oustd=cXX
, oùXX
est89
,90
,99
ou11
, et non-pedantic
ou-pedantic-errors
. Même cela est une simplification excessive; voir le manuel pour plus de détails.Utilisez cette commande
pour l'obtenir
la source