La réponse de Mehrad doit être élargie pour qu'elle fonctionne. De même, son commentaire
/* MYVARI(A)BLE est indéfini ici */
n'est pas correct ; pour tester une variable indéfinie, il y a le simple test #ifndef MYVARIABLE
.
Après ce test, cependant, son expression conduit à une solution correcte de la question initiale. J'ai testé que ce code fonctionne, pour des valeurs indéfinies, définies mais vides, et non vides de la macro MYVARIABLE :
#ifndef MYVARIABLE
/* MYVARIABLE is undefined here */
#elif ~(~MYVARIABLE + 0) == 0 && ~(~MYVARIABLE + 1) == 1
/* MYVARIABLE is defined with no value here */
#else
/* MYVARIABLE is defined here */
#endif
El #elif
déclaration ~(~MYVARIABLE + 0) == 0 && ~(~MYVARIABLE + 1) == 1
fonctionne comme suit :
- Lorsque
MYVARIABLE
est défini mais vide, il s'étend à ~(~+0) == 0 && ~(~+1) == 1
ce qui donne 0==0 && 1==1
(la double négation ~~ étant un opérateur d'identité).
- Lorsque
MYVARIABLE
est défini comme une valeur numérique, disons n, il se développe en ~(~n+0)==0 && ~(~n+1)==1
. Sur le côté gauche de &&
l'expression ~(~n+0)==0
évalue à n==0
. Mais avec n==0
le côté droit s'évalue à ~(~0+1)==1
avec ~0 étant -1 à ~(-1+1)==1
entonces ~0==1
et enfin -1==1
ce qui est évidemment faux.
- Lorsque
MYVARIABLE
est défini à une valeur non numérique, le précompilateur réduit tous les symboles inconnus à 0, et nous obtenons à nouveau le cas précédent avec n==0.
Mon code de test complet (enregistré dans le fichier test.c) :
#include <stdio.h>
int main() {
printf("MYVARIABLE is "
#ifndef MYVARIABLE
"undefined"
#elif ~(~MYVARIABLE + 0) == 0 && ~(~MYVARIABLE + 1) == 1
"defined without a value"
#else
"defined with this value : %i", MYVARIABLE
#endif
);
printf("\n");
}
Avec le préprocesseur GNU cpp vous pouvez expérimenter pour voir quel code est produit :
# undefined
cpp test.c
#defined without a value
cpp -DMYVARIABLE= test.c
#defined wit an implicit value 1
cpp -DMYVARIABLE test.c
#defined wit an explicit value 1
cpp -DMYVARIABLE=1 test.c
#defined wit an explicit value a
cpp -DMYVARIABLE=a test.c
ou le résultat de la compilation et de l'exécution (sous certains linux)
$ gcc -o test test.c ; ./test
MYVARIABLE is undefined
$ gcc -DMYVARIABLE= -o test test.c ; ./test
MYVARIABLE is defined without a value
$ gcc -DMYVARIABLE -o test test.c ; ./test
MYVARIABLE is defined with this value : 1
$ gcc -DMYVARIABLE=1 -o test test.c ; ./test
MYVARIABLE is defined with this value : 1
$ gcc -DMYVARIABLE=a -o test test.c ; ./test
test.c: In function ‘main’:
<command-line>:0:12: error: ‘a’ undeclared (first use in this function)
...
Dans la dernière exécution, où MYVARIABLE est défini comme 'a', l'erreur n'est pas une erreur dans la définition de la macro ; la macro est correctement conduite au dernier cas, "défini avec cette valeur...". Mais cette valeur étant 'a', et 'a' n'étant pas défini dans le code, le compilateur ou le cours doit le signaler.
De cette façon, le dernier cas est un très bon exemple de la raison pour laquelle l'intention de la question originale est très dangereuse : via une macro, l'utilisateur peut introduire n'importe quelle séquence de lignes de programme dans le code à compiler. Vérifier qu'un tel code n'est pas introduit, nécessite beaucoup plus de vérification de la macro sur les valeurs valides. Probablement un script complet est nécessaire, au lieu de laisser cette tâche au prétraitement. Et dans ce cas, quelle est l'utilité de le vérifier aussi dans le prétraitement ?