Existe-t-il une possibilité de convertir les noms des énumérateurs en chaînes en C?
Une façon de faire faire le travail au préprocesseur. Cela garantit également que vos énumérations et chaînes sont synchronisées.
#define FOREACH_FRUIT(FRUIT) \
FRUIT(apple) \
FRUIT(orange) \
FRUIT(grape) \
FRUIT(banana) \
#define GENERATE_ENUM(ENUM) ENUM,
#define GENERATE_STRING(STRING) #STRING,
enum FRUIT_ENUM {
FOREACH_FRUIT(GENERATE_ENUM)
};
static const char *FRUIT_STRING[] = {
FOREACH_FRUIT(GENERATE_STRING)
};
Une fois le préprocesseur terminé, vous aurez:
enum FRUIT_ENUM {
apple, orange, grape, banana,
};
static const char *FRUIT_STRING[] = {
"apple", "orange", "grape", "banana",
};
Ensuite, vous pouvez faire quelque chose comme:
printf("enum apple as a string: %s\n",FRUIT_STRING[apple]);
Si le cas d'utilisation imprime littéralement le nom d'énumération, ajoutez les macros suivantes:
#define str(x) #x
#define xstr(x) str(x)
Alors fais:
printf("enum apple as a string: %s\n", xstr(apple));
Dans ce cas, il peut sembler que la macro à deux niveaux soit superflue, cependant, en raison du fonctionnement de la stringification en C, elle est nécessaire dans certains cas. Par exemple, disons que nous voulons utiliser un #define avec une énumération:
#define foo apple
int main() {
printf("%s\n", str(foo));
printf("%s\n", xstr(foo));
}
Le résultat serait:
foo
apple
C'est parce que str stringifiera l'entrée foo plutôt que de l'étendre pour qu'elle devienne apple. En utilisant xstr, le développement de la macro est effectué en premier, puis ce résultat est stringifié.
Voir Stringification pour plus d'informations.
#define GENERATE_ENUM(ENUM) PREFIX##ENUM,
Dans une situation où vous avez ceci:
J'aime mettre ceci dans le fichier d'en-tête où l'énumération est définie:
la source
enumToString(apple)
que de taper"apple"
? Ce n'est pas comme s'il y avait une sécurité de type n'importe où. À moins que je ne manque quelque chose, ce que vous suggérez ici est inutile et réussit simplement à obscurcir le code.Il n'y a pas de moyen simple d'y parvenir directement. Mais P99 a des macros qui vous permettent de créer automatiquement ce type de fonction:
dans un fichier d'en-tête, et
dans une unité de compilation (fichier .c) devrait alors faire l'affaire, dans cet exemple, la fonction serait alors appelée
color_getname
.la source
J'ai trouvé une astuce de préprocesseur C qui fait le même travail sans déclarer une chaîne de tableau dédiée (Source: http://userpage.fu-berlin.de/~ram/pub/pub_jf47ht81Ht/c_preprocessor_applications_en ).
Énumérations séquentielles
Suite à l'invention de Stefan Ram, des énumérations séquentielles (sans énoncer explicitement l'index, par exemple
enum {foo=-1, foo1 = 1}
) peuvent être réalisées comme cette astuce de génie:Cela donne le résultat suivant:
Énumérations non séquentielles
Puisque je voulais mapper les définitions de codes d'erreur à une chaîne de tableau, afin que je puisse ajouter la définition d'erreur brute au code d'erreur (par exemple
"The error is 3 (LC_FT_DEVICE_NOT_OPENED)."
), j'ai étendu le code de cette manière que vous pouvez facilement déterminer l'index requis pour les valeurs d'énumération respectives :Dans cet exemple, le préprocesseur C générera le code suivant :
Il en résulte les capacités de mise en œuvre suivantes:
la source
Vous n'avez pas besoin de vous fier au préprocesseur pour vous assurer que vos énumérations et chaînes sont synchronisées. Pour moi, l'utilisation de macros a tendance à rendre le code plus difficile à lire.
Utilisation d'énumérations et d'un tableau de chaînes
Remarque: les chaînes du
fruit_str
tableau n'ont pas à être déclarées dans le même ordre que les éléments d'énumération.Comment l'utiliser
Ajout d'un contrôle de temps de compilation
Si vous avez peur d'oublier une chaîne, vous pouvez ajouter la vérification suivante:
Une erreur serait signalée au moment de la compilation si la quantité d'éléments d'énumération ne correspond pas à la quantité de chaînes dans le tableau.
la source
Une fonction comme celle-là sans valider l'énumération est un peu dangereuse. Je suggère d'utiliser une instruction switch. Un autre avantage est que cela peut être utilisé pour les énumérations qui ont des valeurs définies, par exemple pour les indicateurs où les valeurs sont 1,2,4,8,16 etc.
Mettez également toutes vos chaînes enum ensemble dans un seul tableau: -
définir les indices dans un fichier d'en-tête: -
Cela facilite la production de différentes versions, par exemple si vous souhaitez créer des versions internationales de votre programme avec d'autres langues.
En utilisant une macro, également dans le fichier d'en-tête: -
Créez une fonction avec une instruction switch, cela devrait renvoyer un
const char *
car les chaînes statiques consts: -Si vous programmez avec Windows, les valeurs ID_ peuvent être des valeurs de ressources.
(Si vous utilisez C ++, toutes les fonctions peuvent avoir le même nom.
)
la source
Une alternative plus simple à la réponse "Enums non séquentiels" de Hokyo, basée sur l'utilisation d'indicateurs pour instancier le tableau de chaînes:
la source
Je fais généralement ceci:
la source