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

Langage C++ Discussion :

Problème avec la methode c_str() de std::string


Sujet :

Langage C++

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Août 2007
    Messages
    32
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 32
    Par défaut Problème avec la methode c_str() de std::string
    Bonjour,

    Je suis sous linux, et j'utilise GCC ( gcc version 4.3.2 (Debian 4.3.2-1.1) )
    J'ai remarqué un problème étrange en utilisant la classe string, de la STL.
    Les deux lignes suivantes ne donnent pas le même résultat dans tous les cas :

    cout << ma_string << endl;
    cout << ma_string.c_str() << endl;

    Ce n'est pas un problème d'affichage, car un parcours de la chaîne renvoyée par c_str() (via un pointeur sur caractère) me confirme qu'elle ne contient pas les mêmes données. En fait, elle est tronquée.


    Voici, plus en détail, la chaine avec laquelle j'obtiens ce résultat :

    INSERT INTO health.grp_data (entete_id, groupe_id, grp_data_numero_groupe, grp_data_data, grp_data_prestation_offset) VALUES (18002, 6, 1160, $$1160|000000000000|0|$$, 0) RETURNING grp_data_id

    Quand je reste en mode "chaine C++", l'intégralité s'affiche.
    Quand je passe en mode "chaine C", via c_str(), j'obtiens la chaine suivante :

    INSERT INTO health.grp_data (entete_id, groupe_id, grp_data_numero_groupe, grp_data_data, grp_data_prestation_offset) VALUES (18002, 6, 1160, $$1160|


    Comme vous pouvez le constater, elle se coupe, bizarrement, au début d'une suite de zéros. Se pourrait-il qu'elle soit interprétée, par erreur, comme une fin de chaîne par l'implémentation ?
    Est-ce un problème connu ? Généralisé ?
    Y'a-t'il une solution simple qui me permettrait d'éviter ce genre de problèmes ? (remplacer toutes les "string" par des objets d'une classe maison est difficilement envisageable, vu la taille de notre projet...)


    Merci par avance pour vos réponses.

  2. #2
    Membre Expert Avatar de Astraya
    Homme Profil pro
    Consommateur de café
    Inscrit en
    Mai 2007
    Messages
    1 048
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Consommateur de café
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 048
    Par défaut
    Bonjour,
    Ce fais n'est pas présent sur le compilateur de microsoft 2008. J'ai essayer avec le code suivant et la totalité s'affiche:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    std::string tmp("INSERT INTO health.grp_data (entete_id, groupe_id, grp_data_numero_groupe, grp_data_data, grp_data_prestation_offset) VALUES (18002, 6, 1160, $$1160|000000000000|0|$$, 0) RETURNING grp_data_id");
    std::cout << tmp << std::endl;
    const char* ch = tmp.c_str();
    std::cout << ch << std::endl;
    effectue tu d'autres traitements en dehors de ton exemple?

  3. #3
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    La principale raison que je peux voir pour ce genre de comportement, c'est si la chaîne contient un '\0' (à l'endroit où elle est tronquée). En effet, ce caractère n'a aucune signification particulière pour une chaîne C++, alors qu'elle marque la fin d'une chaîne C.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  4. #4
    Membre averti
    Profil pro
    Inscrit en
    Août 2007
    Messages
    32
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 32
    Par défaut
    Citation Envoyé par Astraya Voir le message
    Bonjour,
    Ce fais n'est pas présent sur le compilateur de microsoft 2008. J'ai essayer avec le code suivant et la totalité s'affiche:

    effectue tu d'autres traitements en dehors de ton exemple?

    Oui, il y a d'autres traîtements, mais pas entre les deux affichages. J'ai d'ailleurs tenté, après l'affichage de c_str() de réafficher la chaîne, la totalité s'affiche à nouveau. Donc, pas de perte de données entre temps, uniquement dans le résultat de c_str().


    Citation Envoyé par JolyLoic Voir le message
    La principale raison que je peux voir pour ce genre de comportement, c'est si la chaîne contient un '\0' (à l'endroit où elle est tronquée). En effet, ce caractère n'a aucune signification particulière pour une chaîne C++, alors qu'elle marque la fin d'une chaîne C.

    Ah, ça, c'est une remarque très intéressante ! En fait, je passe par c_str() pour parcourir la chaîne, et faire des conversions, caractère par caractère (plus simple, pour moi, que de passer par un itérateur). Mais, justement, peut-être qu'un parcours par itérateur révèlerait des choses intéressantes. Je vais y jeter un oeil dès demain.

    Je vous tiens au courant. Merci !

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Août 2007
    Messages
    32
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 32
    Par défaut
    Ok, c'est exactement ça : Présence d'un caractère nul, évidemment non affiché, mais qui nous pourrit la conversion.

    Merci encore pour les réponses !

  6. #6
    Membre Expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Par défaut
    Citation Envoyé par kzwix Voir le message
    Ah, ça, c'est une remarque très intéressante ! En fait, je passe par c_str() pour parcourir la chaîne, et faire des conversions, caractère par caractère (plus simple, pour moi, que de passer par un itérateur). Mais, justement, peut-être qu'un parcours par itérateur révèlerait des choses intéressantes. Je vais y jeter un oeil dès demain.

    Je vous tiens au courant. Merci !
    Ca, c'est Interdit(tm). std::string::c_str() renvoie une chaine de caractère constante. Le standard ne dit même pas que cette chaine est effectivement stockée dans l'objet std::string. Pire, dans certains cas, une implémentation particulière peut utiliser le fait que cette chaine est constante pour proposer des optimisations (copy-on-write).

    Bref: tu n'as pas le droit de modifier une chaine en passant par std::string::c_str().

    Si tu souhaites la modifier, tu dois passer par les accesseurs disponibles, qui sont :

    • operator[]()
    • les itérateurs


    Toute autre solution nécessite de passer outre les conditions définies par le standard C++, avec pour conséquence évidente que le fonctionnement de tes programmes n'est plus garanti. Tu crois que c'est plus simple - sauf que, comme tu l'as remarqué toi même, tu n'es pas à l'abri d'un bug qui va finalement te faire perdre ton temps. La simplicité en prends un coup, non ?

    A noter que si tu n'as pas envie d'écrire un code trop lourd, tu peux tout à fait créer un alias de type sur les types itérateurs (avec typedef). Le code suivant se retrouve très régulièrement dans mon code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    void function(const std::string& s)
    {
      typedef std::string::iterator i_type;
     
      // utilisation de i_type à la place de std::string::iterator. 
    }
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  7. #7
    Membre averti
    Profil pro
    Inscrit en
    Août 2007
    Messages
    32
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 32
    Par défaut
    Citation Envoyé par Emmanuel Deloget Voir le message
    Ca, c'est Interdit(tm). std::string::c_str() renvoie une chaine de caractère constante. Le standard ne dit même pas que cette chaine est effectivement stockée dans l'objet std::string. Pire, dans certains cas, une implémentation particulière peut utiliser le fait que cette chaine est constante pour proposer des optimisations (copy-on-write).

    Bref: tu n'as pas le droit de modifier une chaine en passant par std::string::c_str().

    Si tu souhaites la modifier, tu dois passer par les accesseurs disponibles, qui sont :

    • operator[]()
    • les itérateurs


    Toute autre solution nécessite de passer outre les conditions définies par le standard C++, avec pour conséquence évidente que le fonctionnement de tes programmes n'est plus garanti. Tu crois que c'est plus simple - sauf que, comme tu l'as remarqué toi même, tu n'es pas à l'abri d'un bug qui va finalement te faire perdre ton temps. La simplicité en prends un coup, non ?
    Houlà, j'ai pas dit que je modifiais la chaîne en elle-même, hein ! Non, je convertis le caractère lu, et j'écris le caractère obtenu dans une AUTRE chaîne. Et ça n'aurait rien à voir avec les conséquences que tu décris, puisque je parlais de ce que retournait c_str(), pas d'un massacre de ma chaîne à l'aide de pointeurs


    Cela dit, merci tout de même de ton intervention. La cause de l'erreur, au final, était des caractères \0 qui se cachaient dans la chaîne, parce qu'un collègue assignait un nombre à une chaîne, au lieu d'assigner la représentation texte de ce nombre. Total, la chaîne en question prenait cet int pour un char, et comme l'int valait 0, elle prenait la valeur "\0". Quand, ensuite, on concaténait la chaîne avec d'autres, le caractère nul restait, car il faisait partie de la string... et c'est comme ça qu'on obtenait ce joyeux ratage

    Donc voilà, c'est résolu de chez résolu, et j'ai appris des choses au passage. Donc merci

  8. #8
    Membre Expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Par défaut
    Citation Envoyé par kzwix Voir le message
    Houlà, j'ai pas dit que je modifiais la chaîne en elle-même, hein ! Non, je convertis le caractère lu, et j'écris le caractère obtenu dans une AUTRE chaîne. Et ça n'aurait rien à voir avec les conséquences que tu décris, puisque je parlais de ce que retournait c_str(), pas d'un massacre de ma chaîne à l'aide de pointeurs
    Il faudrait que je prenne un poste de lecteur de forum à plein temps. Sans ça, je m'apperçois que je fais des erreurs de lecture grossières
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

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

Discussions similaires

  1. Problème avec la methode c_str()
    Par Sleeping Lionheart dans le forum C++
    Réponses: 15
    Dernier message: 06/05/2009, 18h26
  2. Problème avec la method Get
    Par Mat67 dans le forum Langage
    Réponses: 10
    Dernier message: 25/06/2007, 12h13
  3. Réponses: 3
    Dernier message: 12/04/2007, 10h47
  4. Réponses: 2
    Dernier message: 24/10/2005, 10h23
  5. [IDHTTP] Problème avec la methode post (login:pass@ww.url)
    Par Rayek dans le forum Web & réseau
    Réponses: 5
    Dernier message: 11/07/2005, 10h03

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