IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

Strtol - Vérification des erreurs ?


Sujet :

C

  1. #1
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 491
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 491
    Billets dans le blog
    1
    Par défaut Strtol - Vérification des erreurs ?
    Bonjour

    Je travaille sur un programme qui n'a pas le droit de planter, je me dois donc de vérifier toutes les erreurs possibles. A un moment du programme, j'ai besoin de convertir des chaînes en nombre. J'ai dans un premier temps utilisé un atoi, étant presque certain que c'étaient des chaines ne contenant que des chiffres qui allaient arriver.

    Mais n'était jamais trop prudent, et comme atoi pourrait bien planter pour d'autres raisons, je me tourne donc vers strol pour une meilleure vérification des erreurs.




    A partir du man, je trouve assez délicat de faire quelque chose simple...

    1) Il faudrait tester si le retour est nul, au quel cas, il peut y avoir une erreur. Sauf que la chaine à convertir peut effectivement être "0" ou "00000", et alors la convertion est correct même si le retour est nul.
    2) Si le retour est nul, il faut donc tester la chaine d'origine avec le contenu **endptr. S'il y a égalité, alors c'est une erreur, sinon, il n'y a pas d'erreur.
    3) Il faut aussi tester si le retour vaut LONG_MAX ou LONG_MIN, auquel cas, c'est une erreur.

    Est-ce correct ? Il y a t-il plus simple ?


    Merci d'avance !!!

  2. #2
    Invité(e)
    Invité(e)
    Par défaut
    L'inconvénient de strtol est qu'on a vite fait de confondre chaine invalide et zero.

    Il y a t-il plus simple ?
    De mon point de vue, une solution simple* serait d'utiliser sscanf :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int entier;
    if(1 == sscanf(chaine_a_convertir, "%d", &entier)) {
        /* la conversion a réussi */
    } else {
        /* la conversion a échoué */
    }
    * simple car le retour de sscanf nous dit si la conversion s'est bien passée.

  3. #3
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Par défaut
    Citation Envoyé par mabu Voir le message
    L'inconvénient de strtol est qu'on a vite fait de confondre chaine invalide et zero.
    C'est vrai avec atoi(), pas avec strtol() dont le paramètre endptr sert à gérer ce cas d'erreur.

    Il permet également, ce que ne permet pas facilement sscanf(), de savoir si tout à été converti ou si la conversion s'est arrêtée sur une caractère non convertible et, le cas échéant, où la conversion s'est arrêtée.

    Concernant le troisième point de Bktero, LONG_MAX ou LONG_MIN ne sont pas nécessairement des erreurs (il est possible que ce soit le résultat correct de la conversion), il faut en plus tester errno.
    J'ignore comment se comporte sscanf() dans ce cas de figure, il faudrait que je jette un œil dans la norme.

    strtol() est certes un peu laborieux à utiliser correctement mais permet un contrôle assez fin des erreurs.

  4. #4
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 491
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 491
    Billets dans le blog
    1
    Par défaut
    J'avoue que sscanf est très tentante. Elle permet simplement de vérifier que la conversion a été faite. Ce qui arrive en entrée de la fonction de conversion est déjà pas mal contrôlée en amont. En fait, j'ai une liste de nombres séparés par des virgules dans un fichier de configuration ; le binaire est lancé par un shell qui vérifie le bon format de la chaine ; le binaire découpe la chaîne avec strtok. Donc a priori, si ça arrive à la conversion, ce sont des chiffres uniquement.


    En revanche, oui, ça parait clair d'avoir un contrôle plus détaillé de la conversion... Mais j'ai toujours un peu de mal à juger de tous les cas possibles. Mon idée était la suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    char * pt_erreur= NULL ;
    long monNombre = 0 ;
    char maChaine[] = "42";
     
    monNombre = strtol( maChaine , &pt_erreur , 10);
     
    if(monNombre = 0)
    {
         // Et là, ça se corse...
    }
    Ca se corse, car la doc dit "si endptr n'est pas NULL". Ca sous-entend qu'on a donné un "vrai" pointeur en paramètre et non écrit NULL ?

    On a ensuite "en particulier, si *nptr n'est pas `\0' et si **endptr vaut `\0' en retour, la chaîne entière est valide". Il faut donc, dans le cas d'un retour nul, faire un strcpy entre la chaine d'origine et "\0" et regarde si *pt_erreur = '\0' ?

    Mon LONG_MIN et MAX, ça serait quand même de la chance que ça ne soit pas une erreur non ? Ça voudrait dire que de toutes les valeurs de trop grande amplitude, notre nombre est comme par hasard égale à l'une des ces 2 bornes....

  5. #5
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 491
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 491
    Billets dans le blog
    1
    Par défaut
    Je me suis pris par la main, et j'ai codé un truc. J'ai trouvé un cas où sscanf passe à côté d'une erreur et où strtol s'en sort bien.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
     
    #include <stdio.h>
     
    int main(void)
    {
        char maChaine[] = "  -1116 5";
        printf("Resultat = '%d' \n",convertion_sscanf(maChaine));
        printf("Resultat = '%d' \n",convertion_strtol(maChaine));
    }/*main*/
     
     
    int convertion_sscanf(char maChaine[])
    {
        int monEntier = 0;
        printf("\n--- Convertion avec sscanf ---\n");
        if(1 == sscanf(maChaine,"%d",&monEntier))
        {
            printf("Succes de la convertion ^^\n");
        }
        else
        {
            printf("Erreur de la convertion !\n");
        }
        return monEntier;
    }/*convertion_sscanf*/
     
     
    int convertion_strtol(char maChaine[])
    {
        long monEntier = 0;
        char *pt_erreur = NULL;
        printf("\n--- Convertion avec strtol ---\n");
        monEntier = strtol(maChaine, &pt_erreur, 10);
        printf("Contenu de mon pointeur d'erreur : %c \n",*pt_erreur);
        if(maChaine[0] != '\0' && *pt_erreur == '\0')
        {
            printf("Succes de la convertion ^^\n");
        }
        else
        {
            printf("Erreur de la convertion !\n");
        }
     
        return (int) monEntier;
    }/*convertion_strtol*/
    Voyez-vous des erreurs ou des omissions dans ce code ?

    Merci d'avance

  6. #6
    Membre Expert
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 104
    Par défaut
    Ca se corse, car la doc dit "si endptr n'est pas NULL". Ca sous-entend qu'on a donné un "vrai" pointeur en paramètre et non écrit NULL ?

    On a ensuite "en particulier, si *nptr n'est pas `\0' et si **endptr vaut `\0' en retour, la chaîne entière est valide". Il faut donc, dans le cas d'un retour nul, faire un strcpy entre la chaine d'origine et "\0" et regarde si *pt_erreur = '\0' ?
    Même si on peut envoyer NULL comme second argument à la fonction, ce pointeur (*endptr) est essentiel pour connaître l'adresse du premier caractère invalide et donc de juger le degré de réussite de la conversion.

    Par déduction, on peut donc dire que (cas où *endptr n'est pas NULL) :

    1) si *nptr est différent de '\0' (c'est-à-dire que la chaîne à scanner n'est pas vide) et que **endptr vaut '\0' (c'est-à-dire que le premier caractère invalide est le caractère de fin de chaîne), la conversion s'est totalement bien passée. Cas d'une conversion de chaine "1234" par exemple.

    2) si nptr et *endptr sont différents (c'est-à-dire qu'il y a au moins un caractère valide) alors que **endptr est différent de '\0' (c'est-à-dire que le premier caractère invalide trouvé est un caractère autre que celui de fin de chaîne), la conversion a donc partiellement réussi. Cas d'une conversion d'une chaine "1234hello" (si on utilise une base non exotique bien sûr) ou "9876,122" (cela peut donc servir de méthode alternative pour scanner un CSV, une méthode parmi d'autres [comme celle du découpage de chaine comme tu le fais]) par exemple.

    3) si nptr et *endptr sont égaux, alors le premier caractère trouvé est invalide : la conversion a totalement échoué et la fonction renvoie 0. Cas de la conversion d'une chaine telle que "s0123" (si on n'utilise pas une base exotique) ou "" par exemple.

    Par conséquent, si on envoie NULL comme second argument (*endptr), on ne peut donc pas savoir si la conversion a partiellement ou totalement réussi dans le cas où la fonction renvoie une valeur autre que 0 ni si elle a partiellement réussi, totalement réussi ou totalement échoué lorsque la fonction renvoie la valeur 0. D'où l'importance d'utiliser un pointeur autre que NULL comme second argument (même si la fonction le permet), afin d'effectuer tous ces tests.

    C'est ça qu'ils veulent expliquer dans cette partie :
    Si endptr n'est pas NULL, strtol() stocke l'adresse du premier caractère invalide dans *endptr. S'il n'y avait aucun chiffre valide, strtol() stocke la valeur originale de nptr dans *endptr (et renvoie 0). En particulier, si *nptr n'est pas `\0' et si **endptr vaut `\0' en retour, la chaîne entière est valide.

  7. #7
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 491
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 491
    Billets dans le blog
    1
    Par défaut
    Ce que tu dis correspond à ce que j'ai obtenu en testant mon bout de code, et donc valide ce petit bout de code



    Merci à tous pour vos réponses, je marque le sujet comme résolu

  8. #8
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Par défaut
    Citation Envoyé par jeroman Voir le message
    1) si *nptr est différent de '\0' (c'est-à-dire que la chaîne à scanner n'est pas vide) et que **endptr vaut '\0' (c'est-à-dire que le premier caractère invalide est le caractère de fin de chaîne), la conversion s'est totalement bien passée. Cas d'une conversion de chaine "1234" par exemple.

    2) si nptr et *endptr sont différents (c'est-à-dire qu'il y a au moins un caractère valide) alors que **endptr est différent de '\0' (c'est-à-dire que le premier caractère invalide trouvé est un caractère autre que celui de fin de chaîne), la conversion a donc partiellement réussi. Cas d'une conversion d'une chaine "1234hello" (si on utilise une base non exotique bien sûr) ou "9876,122" (cela peut donc servir de méthode alternative pour scanner un CSV, une méthode parmi d'autres [comme celle du découpage de chaine comme tu le fais]) par exemple.

    3) si nptr et *endptr sont égaux, alors le premier caractère trouvé est invalide : la conversion a totalement échoué et la fonction renvoie 0. Cas de la conversion d'une chaine telle que "s0123" (si on n'utilise pas une base exotique) ou "" par exemple.
    Juste une petite précision parce que la formulation du man n'est pas très clair je trouve.
    Dans l'exemple de Bktero, c'est *pt_erreur qu'il faut comparer à '\0' pour savoir si tout a été bien converti et non **pt_erreur.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [Débutant] vérification des erreurs de code
    Par VirtualSlide dans le forum MATLAB
    Réponses: 3
    Dernier message: 06/07/2013, 19h10
  2. vérification des erreurs
    Par oprian dans le forum Macros et VBA Excel
    Réponses: 3
    Dernier message: 01/12/2007, 15h52
  3. vérification des erreurs d'un code C++
    Par nadjib2007 dans le forum C++Builder
    Réponses: 15
    Dernier message: 30/08/2007, 06h29
  4. [VBA-E] vérification des erreurs d'arrière plan
    Par WagaSeb dans le forum Macros et VBA Excel
    Réponses: 2
    Dernier message: 12/02/2007, 14h41
  5. [LG]gestion des erreurs
    Par frontin dans le forum Langage
    Réponses: 3
    Dernier message: 29/11/2003, 23h41

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo