2010-08-08 5 views
3

Voici une situation typique de notre base de code.scanf() avec C++ enums

enum ConfigOption { CONFIG_1=1, CONFIG_2=2, CONFIG_3=3 } 

ConfigOption cfg1, cfg2; 

sscanf(s, "%d", &cfg1); 

Ceci est un logiciel de simulation utilisé en interne. Non distribué La facilité de maintenance et la correction sont importantes. Portabilité et interface utilisateur - pas vraiment. Le problème est enum en C++ n'est pas nécessairement int. Nous obtenons donc un avertissement du compilateur, et peut obtenir un comportement incorrect lors de l'utilisation d'un compilateur différent ou lorsque les optimisations sont activées. Une solution consiste simplement à lancer &cfg à int*. Cependant, ceci n'attrapera pas les cas où le compilateur a décidé d'allouer autre chose que int au enum.

Je suggère la solution suivante:

template<typename T> inline 
int& eint(T& enum_var) { 
    assert(sizeof(T) == sizeof(int)); 
    return (int&)enum_var; 
} 

Et maintenant, on utilise scanf comme suit:

sscanf(s, "%d", &eint(cfg1)); 

J'aimerais entendre des opinions et d'autres solutions (mieux) au problème ci-dessus. Gardez à l'esprit que l'un des objectifs est de garder le code simple. Ce n'est pas de la «qualité de production» et plus vous ajoutez, plus la maintenance devient difficile.

+1

Depuis la 'sizeof (T) est évalué' Au moment de la compilation, je suggérerais une assertion statique (à la compilation) (par exemple 'BOOST_STATIC_ASSERT'), donc vous obtiendrez une erreur * compilateur * si la taille n'est pas correcte. Et si vous le faites, vous pouvez trouver l'énumération incriminée, et la corriger en utilisant la suggestion de Nils ci-dessous. – UncleBens

Répondre

4

Si vous avez un compilateur moderne comme VS2010 vous pouvez spécifier la taille des éléments ENUM

enum class ConfigOption: unsigned int {CONFIG_1=1, CONFIG_2=2, CONFIG_3=3}; 

son nouveau en C++ 0x

+0

cool! Belle fonctionnalité. –

+0

Malheureusement, nous utilisons toujours une ancienne version de gcc. Pourtant, cela semble la solution la plus propre, donc je vais l'accepter. – nimrodm

0

Vous pouvez essayer d'utiliser boost::lexical_cast, ou si vous n'utilisez pas boost et que vous ne souhaitez pas commencer à l'utiliser dans ce cas, vous pouvez simplement en écrire une version simplifiée. Pour un exemple, jetez un oeil at this SO answer.

+0

'boost :: lexical_cast' repose sur l'opérateur de flux' <<' and '>> 'surcharges. Cela fonctionnerait avec une énumération seulement si ces opérateurs sont surchargés pour cette énumération. – UncleBens

2

Ma solution serait de forcer l'enum à une taille minimum. C'est ce que Microsoft a fait pour leurs énumérations dans leurs fichiers d'en-tête DirectX (une belle astuce que je dois admettre).

Ils la taille appliquées enum être égal à un entier en ajoutant un ENUM factice comme ceci:

typedef enum 
{ 
    fooo = 1, 
    baar = 2, 
    ___Force32Bit = ~0UL 
} MyEnum; 

Maintenant, le ENUM toujours au moins la taille d'un int.

Si vous voulez vous pouvez prendre ce sur le dessus .. Celui-ci force la taille de l'ENUM à une longue longue:

typedef enum 
{ 
    fooo = 1, 
    baar = 2, 
    ___Force64Bit = ~0ULL 
} MyEnum; 

Je sais, ce n'est pas une solution super propre. Je pense qu'une telle solution n'existe pas et l'application d'une taille minimale a bien fonctionné pour moi jusqu'ici. Vous devrez peut-être ajuster le code si vous passez du code 32 à 64 bits, mais généralement dans ces situations, vous devez revoir certaines parties du code de toute façon, donc pas de gros problème.

BTW - désolé pour le code C, je sais que la question a été étiqueté comme C++, mais je suis un gars :-) C-

1

Pourquoi ne pas lire tout comme une int réelle?

enum ConfigOption { CONFIG_1=1, CONFIG_2=2, CONFIG_3=3 }; 
ConfigOption cfg1; 

int i; 
sscanf(s, "%d", &i); 
cfg1 = i; 

Et cette façon, vous pouvez faire la validité plus complète vérifie aussi (comme les tests que l'entier de lecture est dans la plage de votre type enum).

(Bien sûr, si vous êtes tous préoccupés par la détection des erreurs, pour l'analyse syntaxique simple comme cela, vous devriez utiliser strtol ou strtoul au lieu de sscanf.)

+0

Correct, mais ennuyeux (et vous avez toujours besoin d'un casting pour l'assigment). Nous en avons des tonnes ... – nimrodm