2010-11-11 14 views
1

Je rencontre un problème gênant avec une fonction C++ que j'ai écrite et dont le but est de valider l'entrée de l'utilisateur. La fonction lit l'entrée de l'utilisateur, vérifie s'il s'agit d'un nombre et, si c'est le cas, si elle est dans la plage [min, max].Dysfonctionnement de la chaîne de caractères vers un entier non signé

Le problème se produit lorsque j'appelle la fonction de modèle avec un type non signé, comme size_t et l'entrée est un nombre négatif. Le flux de chaîne convertit la chaîne en quelque chose comme 4294967291. Je peux voir que le programme convertit les données en une valeur proche de la valeur maximum du type de données non signé (défini dans l'en-tête numeric_limits) mais ma question est pourquoi, depuis l'instruction if devrait s'arrêter à sstream >> value?

Mon code:

template <class T> 
T getNumberInput(std::string prompt, T min, T max) { 
    std::string input; 
    T value; 

    while (true) { 
     try { 
      std::cout << prompt; 
      std::cin.clear(); 
      std::getline(std::cin, input); 
      std::stringstream sstream(input); 

      if (input.empty()) { 
       throw EmptyInput<std::string>(input); 
      } else if (sstream >> value && value >= min && value <= max) { 
       std::cout << std::endl; 
       return value; 
      } else { 
       throw InvalidInput<std::string>(input); 
      } 
     } catch (EmptyInput<std::string> & emptyInput) { 
      std::cout << "O campo não pode ser vazio!\n" << std::endl; 
     } catch (InvalidInput<std::string> & invalidInput){ 
      std::cout << "Tipo de dados inválido!\n" << std::endl; 
     } 
    } 
} 

Merci pour votre temps!

+0

Ne pas passer un type non signé? – Mud

Répondre

2

Dans l'arithmétique de C comportant un type unsigned avec n bits de valeur, est garanti d'être modulo 2^n . Cela signifie que tout résultat est recopié dans la plage 0 à 2^n -1, en ajoutant ou en soustrayant un multiple approprié de 2^n. Cela est également vrai dans C.

Vous devez donc vérifier l'entrée pour le signe moins, ou ajouter une autre vérification. En passant, votre if avec >> et && a eu un effet sur mon mauvais code. Je ne peux jamais me souvenir des précédents de l'opérateur pour >> par rapport à &&. Je suppose que s'il est compilé, il doit être OK, car >> ne peut pas prendre une valeur de droite. Vérification ... OK, mais j'utiliserais des parenthèses pour clarifier cela.

De même, sur la structure du code, il serait judicieux de séparer la chose d'entrée interactive de la vérification de l'entrée. Par exemple, pouvez-vous utiliser un de ces codes dans un programme GUI, avec une entrée d'un champ d'édition? Non, pas comme il est ...

Vive & HTH.,

+1

Merci pour l'explication théorique. Cela m'a aidé à comprendre le problème. Ajouté le contrôle de signe moins et cela fonctionne parfaitement: 'if (entrée [0] == '-' && std :: numeric_limits :: min() == 0)'. A propos du mauvais code, vous aviez tout à fait raison, donc j'ai résolu cela aussi: 'if ((sstream >> valeur) && (valeur> = min) && (valeur <= max))'. En effet, il est plus lisible et ne laisse aucune place au doute. –

+0

Enfin, mais pas au moins, sur la structure du code, je pense que la solution serait séparée de la fonction en deux, où l'un aurait l'entrée de l'utilisateur et l'autre, le validerait. J'ai juste un doute noob. Dois-je laisser le bloc try and catch dans le getter ou gérer complètement les exceptions dans le validater? –

+0

@renatorodrigues: il serait naturel de garder le contrat de la fonction que vous avez, et cela inclut sa réponse aux exceptions. J'ai envisagé plus d'un refactoring comme le déplacement du code après 'getline' et vers le bas' catch', vers une fonction séparée qui prend une chaîne et produit un nombre (ou lance si elle ne le peut pas). Cheers, –

1

Alf a déjà répondu, mais j'ai eu deux ou trois autres pensées. Tirez le code qui extrait l'entrée du bloc try. Vous n'attrapez aucune exception qu'il pourrait lancer, donc il ne communique pas l'intention aussi bien. Le bloc try devrait commencer juste avant le if (input.empty()) ... Ensuite, tirez toutes les choses dans le bloc try dans une seule fonction de validation. Cela nettoie le code ici. Pour une utilisation dans une interface graphique, cependant, vous voudriez créer une fonction qui obtient juste l'entrée sans validation et exposer la fonction de validation. Ensuite, l'utilisateur peut gérer les exceptions de validation si nécessaire. Bien que dans ce cas, je ne vois pas d'avantage à utiliser des exceptions par opposition à de simples codes d'erreur pour la validation.

Espérons que cela aide,

+0

Eh bien, c'est sûr que ça aide. Merci! –