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++Builder Discussion :

Le sprintf de AnsiString, bug ou pas?


Sujet :

C++Builder

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre expérimenté
    Homme Profil pro
    Enseignant
    Inscrit en
    Mars 2012
    Messages
    164
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2012
    Messages : 164
    Par défaut Le sprintf de AnsiString, bug ou pas?
    en tentant de répondre au problème de commande SQL de faniette, je me souvenu d'un "bug" que j'avais cherché longtemps, soit un "(null)" qui s'insérait dans un champ de table de données.

    J'ai fini par le trouver, me suis demandé s'il y avait un bug dans la méthode de "sprintf" de AnsiString ou si c'était une subtilité qui m'échappait.

    Voilà le bug(?)
    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
     
    {
      AnsiString dest,buf ;
     
      buf = "allo" ;
      dest.sprintf("1- une string: [%s]",buf) ;
      ShowMessage(dest) ;
     
      buf = "" ;
      dest.sprintf("2- une string: [%s]",buf) ;
      ShowMessage(dest) ;
     
      dest.sprintf("3- une string: [%s]",buf.c_str()) ;
      ShowMessage(dest) ;
    }
    Voici ce qui sera affiché:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    1- une string: [allo]
    2- une string: [(null)]
    3- une string: []
    La version #2, vous trouvez ça normal ou pas?

    Et vous trouvez normal, vous voulez m'expliquer pourquoi?

  2. #2
    Membre Expert
    Avatar de DjmSoftware
    Homme Profil pro
    Responsable de compte
    Inscrit en
    Mars 2002
    Messages
    1 044
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Responsable de compte
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 044
    Billets dans le blog
    1
    Par défaut
    Salut Guyt
    dans le cas 2 tu copie un objet d'on tu ignore le contenu puis qu'il n'a pas été initialisé.

    dans le cas 3 c'est bien une chaîne de caractère qui est copiée dans ton buffer
    la méthode .c_str() te retourne le contenu de ton buffer.

    cdlt
    vous trouverez mes tutoriels à l'adresse suivante: http://djmsoftware.developpez.com/
    je vous en souhaite une excellente lecture ...

    A lire : Les règles du forum

  3. #3
    Membre expérimenté
    Homme Profil pro
    Enseignant
    Inscrit en
    Mars 2012
    Messages
    164
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2012
    Messages : 164
    Par défaut
    Citation Envoyé par DjmSoftware Voir le message
    Salut Guyt
    dans le cas 2 tu copie un objet d'on tu ignore le contenu puis qu'il n'a pas été initialisé.
    cdlt
    Na, je comprends toujours pas, y a une subtilité qui m'échappe.

    Juste avant le cas 2, je fais:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    buf= "" ;  // ce qui serait équivalent à buf = AnsiString("") ;
    dest.sprintf("2- une string: [%s]",buf) ;
    J’initialise bien la chaine avec une chaine vide, le contenu je le connais, c'est une string de longueur zéro!

    Tiens, je te balance une autre curiosité:

    Un bouton, une TEdit avec "Edit1" dans sa propriété Text.

    Le code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
     
    void __fastcall TForm3::Button1Click(TObject *Sender)
    {
      AnsiString stg ;
     
      stg.sprintf("%s",Edit1->Text) ;
      ShowMessage(stg) ;
      stg.sprintf("%s",AnsiString(Edit1->Text)) ;
      ShowMessage(stg) ;
    }
    ce qui sera affiché:
    Ouate de phoque???

  4. #4
    Membre Expert
    Avatar de DjmSoftware
    Homme Profil pro
    Responsable de compte
    Inscrit en
    Mars 2002
    Messages
    1 044
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Responsable de compte
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 044
    Billets dans le blog
    1
    Par défaut
    Salut
    Ne confond pas un string qui correspond à un tableau de caractère avec un Ansistring qui lui est un object
    %s correspond à une chaîne de caractère
    Dans ton premier exemple tu ressort le premier caractère normal en Unicode le caractère suivant est un 0
    Dans ton second exemple tu construit un object de type Ansistring à partir d'un object unicode
    La syntaxe correcte est de suffixer avec un c_str ou. T_str
    Cdlt
    vous trouverez mes tutoriels à l'adresse suivante: http://djmsoftware.developpez.com/
    je vous en souhaite une excellente lecture ...

    A lire : Les règles du forum

  5. #5
    Membre expérimenté
    Homme Profil pro
    Enseignant
    Inscrit en
    Mars 2012
    Messages
    164
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2012
    Messages : 164
    Par défaut
    Citation Envoyé par DjmSoftware Voir le message
    Salut
    La syntaxe correcte est de suffixer avec un c_str ou. T_str
    Cdlt
    C'est ce que je faisais depuis un bon bout de temps, sans savoir exactement pourquoi.

    Maintenant je le sais, un gros merci!

  6. #6
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 081
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 081
    Par défaut
    J'avais même déposé une demande sur Quality Central pour que le sprintf (plus élégant et performant que le Format ARRAYOFCONST) émettent un Warning lors de l'utilisation d'un String comme paramètre !

    Je suis d'accord avec Guyt54, la documentation de UnicodeString.sprintf ou AnsiString.sprintf ne fournis aucun avertissement, c'est bien dommage, de plus le lien vers Format renforce la confusion car cette fonction supporte les objets comme paramètre (puisque c'est du code Delphi)

    Venant du Delphi et ayant l'habitude du Format, je pensais utilise ce dernier mais la template ARRAYOFCONST m'a découragé vu le code que cela génère assez infâme du coup, je suis passé au sprintf !
    J'ai bêtement écrit ceci

    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
    {
      UnicodeString S1 = "Chaine S1";
      UnicodeString S2 = "Chaine S2";
      UnicodeString S3 = "Chaine S3";
      UnicodeString S4 = "Chaine S4";
      UnicodeString S5 = "Chaine S5";
      UnicodeString S6 = "Chaine S6";
      UnicodeString LocalStr = "";
     
      for (int i = 0; i < 10; i++)
      {
        S1 += UnicodeString().sprintf(L"%s %d", EmptyStr, i);
        S2 += UnicodeString().sprintf(L"%s %d", "", i);
        S3 += UnicodeString().sprintf(L"%s %d", LocalStr, i);
     
        S4 += Format(L"%s %d", ARRAYOFCONST((EmptyStr, i)));
        S5 += Format(L"%s %d", ARRAYOFCONST(("", i)));
        S6 += Format(L"%s %d", ARRAYOFCONST((LocalStr, i)));
      }
      MemoTrace->Lines->Add("sprintf");
      MemoTrace->Lines->Add(S1);
      MemoTrace->Lines->Add(S2);
      MemoTrace->Lines->Add(S3);
      MemoTrace->Lines->Add("Format");
      MemoTrace->Lines->Add(S4);
      MemoTrace->Lines->Add(S5);
      MemoTrace->Lines->Add(S6);
    }
    Avec ce beau résultat :

    Result actually

    sprintf
    Chaine S1(null) 0(null) 1(null) 2(null) 3(null) 4(null) 5(null) 6(null) 7(null) 8(null) 9
    Chaine S2 0 1 2 3 4 5 6 7 8 9
    Chaine S3(null) 0(null) 1(null) 2(null) 3(null) 4(null) 5(null) 6(null) 7(null) 8(null) 9
    Format
    Chaine S4 0 1 2 3 4 5 6 7 8 9
    Chaine S5 0 1 2 3 4 5 6 7 8 9
    Chaine S6 0 1 2 3 4 5 6 7 8 9

    Result expected

    sprintf
    Chaine S1 0 1 2 3 4 5 6 7 8 9
    Chaine S2 0 1 2 3 4 5 6 7 8 9
    Chaine S3 0 1 2 3 4 5 6 7 8 9
    Format
    Chaine S4 0 1 2 3 4 5 6 7 8 9
    Chaine S5 0 1 2 3 4 5 6 7 8 9
    Chaine S6 0 1 2 3 4 5 6 7 8 9

    Leur réponse sur QC fut : "Please try to add .c_str() as below, because EmptyStr and LocalStr are instances of UnicodeString class."
    Belle Astuce, j'aurais bien aimé qu'elle soit dans la Documentation, j'aurais évité une perte de temps !
    D'ailleurs, c'était aussi pour générer du SQL à la volée via ma couche d'objet persistant tout en utilisant les Parameters pour simplifier le typage des champs\propriétés

    les AnsiString sont des objets en allocation statique, le constructeur défini la chaîne sur un pointeur NULL qui est géré par le C++ tout comme en Delphi, il y avait même une constante prévue à cet effet (avant on ne pouvait pas définir '' ou "" directement, il fallait utiliser la constante EmptyStr

    Et le (null) est tout simplement la valeur du membre privé Data dans la AnsiString !
    Tout en rappelant que Data[-12] pointe sur StrRec et que le code d'allocation des chaines est écrit en Delphi !


    J'ai conservé un petit code (j'ai aussi une version UnicodeString) pour me rappeler de cette surprise !

    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
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    //---------------------------------------------------------------------------
    void __fastcall TLanguageBasicsForm::BtnReveiverAndParametersprintfClick(TObject *Sender)
    {
      MemoTrace->Lines->Add("S.sprintf(\"%s %d\", S, i++);");
      AnsiString SP1 = "Chaine SP1";
      AnsiString SP2 = "Chaine SP2";
      AnsiString SP3 = "Chaine SP3";
      AnsiString SP4 = "Chaine SP4";
      AnsiString SP4c = "Chaine SP4c";
      AnsiString SP5 = "Chaine SP5";
      AnsiString SP6 = "Chaine SP6";
      AnsiString SP6c = "Chaine SP6c";
      AnsiString SP7 = "Chaine SP7";
      AnsiString SF1 = "Chaine SF1";
      AnsiString SF2 = "Chaine SF2";
      AnsiString SF3 = "Chaine SF3";
     
      for (int i = 0; i < 10; i++)
      {
        SP1.sprintf("%s %d", SP1, i);
        SP2 = AnsiString().sprintf("%s %d", SP2, i);
        SP3 += ", ";
        SP3 += AnsiString().sprintf("%d", i);
        SP4 += AnsiString().sprintf("%s %d", EmptyStr, i);
        SP4c += AnsiString().sprintf("%s %d", EmptyStr.c_str(), i);
        SP5 += AnsiString().sprintf("%s %d", "", i);
        AnsiString LocalStr = "";
        SP6 += AnsiString().sprintf("%s %d", LocalStr, i);
        SP6c += AnsiString().sprintf("%s %d", LocalStr.c_str(), i);
        SP7 += AnsiString().sprintf("%s %d", AnsiString(this->ClassName()).c_str(), i);
     
        SF1.Format("%s %d", ARRAYOFCONST((SF1, i)));
        SF2 += AnsiString().Format("%s %d", ARRAYOFCONST((EmptyStr, i)));
        SF3 += AnsiString().Format("%s %d", ARRAYOFCONST((LocalStr, i)));
      }
      MemoTrace->Lines->Add("sprintf");
      MemoTrace->Lines->Add(SP1);
      MemoTrace->Lines->Add(SP2);
      MemoTrace->Lines->Add(SP3);
      MemoTrace->Lines->Add(SP4);
      MemoTrace->Lines->Add(SP4c);
      MemoTrace->Lines->Add(SP5);
      MemoTrace->Lines->Add(SP6);
      MemoTrace->Lines->Add(SP6c);
      MemoTrace->Lines->Add(SP7);
      MemoTrace->Lines->Add("Format");
      MemoTrace->Lines->Add(SF1);
      MemoTrace->Lines->Add(SF2);
      MemoTrace->Lines->Add(SF3);
     
      MemoTrace->Lines->Add("sprintf too params : " + AnsiString().sprintf("a %d b %d c %d", 1, 2, 3, 4, 5, 6));
      MemoTrace->Lines->Add("sprintf missing params : " + AnsiString().sprintf("a %d b %d c %d", 1, 2));
     
      MemoTrace->Lines->Add("sprintf %8x et %08x");
      int i = 123;
      MemoTrace->Lines->Add(AnsiString().sprintf("%8x", i));
      MemoTrace->Lines->Add(AnsiString().sprintf("%08x", i));
      MemoTrace->Lines->Add(AnsiString().sprintf("%01x", i));
      MemoTrace->Lines->Add(AnsiString().sprintf("%d", i));
      MemoTrace->Lines->Add(AnsiString().sprintf("%06d", i));
      MemoTrace->Lines->Add(AnsiString().sprintf("%02d", i));
      bool flag = true;
      MemoTrace->Lines->Add(AnsiString().sprintf("Boolean true = %d", flag));
      flag = false;
      MemoTrace->Lines->Add(AnsiString().sprintf("Boolean false = %d", flag));
    }
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

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

Discussions similaires

  1. bug excel pas ordinaire calendrier fantôme
    Par alsimbad dans le forum Macros et VBA Excel
    Réponses: 7
    Dernier message: 03/12/2006, 18h59
  2. FB: DB vide, impossible de connecter : Bug ou Pas Bug ?
    Par Rica dans le forum Connexion aux bases de données
    Réponses: 1
    Dernier message: 14/05/2005, 11h15

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