61 votes

Pourquoi le préprocesseur C considère-t-il que les valeurs enum sont égales?

Pourquoi ne l' std::cout ligne dans le code suivant s'exécute même si A et B sont différentes?

#include <iostream>

enum T { A = 1, B = 2 };
// #define A 1
// #define B 2

int main() {
#if (A == B)
    std::cout << A << B;
#endif
}

Si j'utilise #define à la place (comme en commentaire), je n'ai pas de sortie que j'attends.

Raison pour laquelle la question:

Je veux avoir un sélecteur de mode pour certains, un code de test dans lequel je peux facilement changer de mode par commenter/décommenter les lignes sur le dessus:

enum T { MODE_RGB = 1, MODE_GREY = 2, MODE_CMYK = 3 };
// #define MODE MODE_RGB
#define MODE MODE_GREY
// #define MODE MODE_CMYK

int main() {
#if (MODE == MODE_RGB)
    // do RGB stuff
#elif (MODE == MODE_GREY)
    // do greyscale stuff
#else
    // do CMYK stuff
#endif

    // some common code

    some_function(arg1, arg2,
#if (MODE == MODE_RGB)
        // RGB calculation for arg3,
#elif (MODE == MODE_GREY)
        // greyscale calculation for arg3,
#else
        // CMYK calculation for arg3,
#endif
        arg4, arg5);
}

Je sais que je peux utiliser des valeurs numériques par exemple

#define MODE 1 // RGB
...
#if (MODE == 1) // RGB

mais elle rend le code moins lisible.

Est-il une solution élégante pour cela?

120voto

Simple Points 4460

Il n'y a pas de macros appelées A ou B , donc sur votre ligne #if , A et B sont remplacées par 0 , vous avez donc réellement:

 enum T { A = 1, B = 2 };

int main() {
#if (0 == 0)
    std::cout << A << B;
#endif
}
 

Le préprocesseur s'exécute avant que le compilateur ne sache rien de votre enum . Le préprocesseur ne connaît que les macros ( #define ).

44voto

Samidamaru Points 960

C'est parce que le préprocesseur oeuvres avant le moment de la compilation.

Comme l'enum définitions se produire au moment de la compilation, A et B seront définies à vide (pp-nombre 0) - et donc égale à la durée de pré-traitement, et donc la sortie de déclaration est incluse dans le code compilé.

Lorsque vous utilisez #define qu'ils sont définis différemment à la durée de pré-traitement et donc la déclaration prend la valeur false.

En ce qui concerne votre commentaire sur ce que vous voulez faire, vous n'avez pas besoin d'utiliser le pré-processeur #if pour ce faire. Vous pouvez simplement utiliser la norme if comme MODE et MODE_GREY (ou MODE_RGB ou MODE_CMYK) sont encore tous définis:

#include <iostream>

enum T { MODE_RGB = 1, MODE_GREY = 2, MODE_CMYK = 3 };

#define MODE MODE_GREY

int main()
{
    if( MODE == MODE_GREY )
        std::cout << "Grey mode" << std::endl;
    else if( MODE == MODE_RGB )
        std::cout << "RGB mode" << std::endl;
    else if( MODE == MODE_CMYK )
        std::cout << "CMYK mode" << std::endl;

    return 0;
}

L'autre option en utilisant uniquement le pré-processeur est pour cela que @TripeHound correctement répondu ci-dessous.

24voto

user2079303 Points 4916

Les identificateurs qui ne sont pas des macros définies sont interprétés comme la valeur 0 dans les directives de préprocesseur conditionnelles. Par conséquent, puisque vous n'aviez pas défini de macros A et B , elles sont toutes deux considérées comme 0 et deux 0 égales.

La raison pour laquelle les identificateurs non définis (destinés au préprocesseur) sont considérés comme 0 est due au fait que cela permet d'utiliser des macros non définies dans le conditionnel sans utiliser #ifdef .

11voto

Ulrich Eckhardt Points 260

Le préprocesseur s'exécute avant le compilateur, ce qui signifie qu'il ne sait rien des symboles définis par le compilateur et qu'il ne peut donc pas agir en fonction de ceux-ci.

10voto

user10063 Points 103

Comme les autres réponses, a déclaré, le préprocesseur C ne pas voir les énumérations. Il s'attend, et ne peut comprendre, les macros.

Par le standard C99, §6.10.1 (sous réserve de l'inclusion):

Après tous les remplacements en raison expansion de macro et de la définition de l'opérateur unaire ont été effectuées, à tous les autres identifiants sont remplacés par les pp-numéro 0

En d'autres termes, dans un #if et #elif directive, toutes les macros qui ne peut pas être développée, car elles n'existent pas/ne sont pas définis, se comporte exactement comme si elles avaient été définie à 0, et donc sera toujours égale les uns des autres.

Vous pouvez attraper probablement involontaire comportement comme ça dans GCC/clang avec l'option d'avertissement -Wundef (vous aurez probablement envie de faire fatale avec -Werror=undef).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X