sprintf

Bonjour,

J'ai un sprintf qui ne fonctionne pas comme je l'attends :

  sprintf(wInfo.ligne0, "Rx: %04d %04d", voie1, voie2);

ça me donne : Rx: 1504 0000 Le problème est que ma variable voie2 (qui est bien numérique) ne contient pas 0!

Pour obtenir ce que je souhaite, je suis obligé d'écrire ceci :

  sprintf(wInfo.ligne0, "Rx: %04d ", voie1);
  sprintf(wInfo.ligne0, "%s%04d ", wInfo.ligne0, voie2);

Est-ce qu'il y une explication?...

A+ Olivier

quel est le type de wInfo.ligne0 : est-ce bien char* ?

Oui, voilà la définition :

char ligne0[20];

La définition est dans une classe :

#ifndef INFO_H
#define INFO_H

#include <SerialLCD.h>
#include <SoftwareSerial.h> //this is a must

class info{
public :
  char ligne0[20];
  char ligne1[20];
  
  info();
  void affecter(char const*, char const*);
  void affiche(SerialLCD*);
};
#endif

Et voilà son utilisation :

info recepteur::debug(){
  // Test : 
  info wInfo;
//  sprintf(wInfo.ligne0, "Rx: %04d %04d", voie1, voie2);
  sprintf(wInfo.ligne0, "Rx: %04d ", voie1);
  sprintf(wInfo.ligne0, "%s%04d ", wInfo.ligne0, voie2);
//  sprintf(wInfo.ligne1, "    %04d %04d", voie3, voie4);
  sprintf(wInfo.ligne1, "    %04d ", voie3);
  sprintf(wInfo.ligne1, "%s%04d ", wInfo.ligne1, voie4);
  return wInfo;
}

J'ai trouvé ! Tu assignes une variable locale, qui est détruite durant le return. Et de plus, tu n'as pas défini un opérateur de copie, ce qui fait que le contenu n'est pas gardé.

Passe ton objet comme paramètre, ou définis une méthode dans cet objet, vu qu'elle le manipule.

Ce qu'il faudrait faire est décrit dans l'excellent livre "Thinking in c++", disponible gratuitement (volumes 1 et 2).

http://www.drbio.cornell.edu/pl47/programming/TICPP-2nd-ed-Vol-one-html/Chapter11.html

Je croyais avoir compris ton explication. J'ai donc modifié ma méthode :

void recepteur::debug(info* wInfo){
  // Test : 
  sprintf((*wInfo).ligne0, "Rx: %04d %04d", voie1, voie2);
  sprintf((*wInfo).ligne1, "    %04d %04d", voie3, voie4);
}

Et je l'appel de cette façon :

  info wDebug;
  rxNeutre.debug(&wDebug);
  wDebug.affiche(currentLCD);

Mais je tombe sur le même problème : Rx: 1504 0000

Mais es-tu sûr que voie2 != 0 ?

XavierMiller:
Ce qu’il faudrait faire est décrit dans l’excellent livre “Thinking in c++”, disponible gratuitement (volumes 1 et 2).

http://www.drbio.cornell.edu/pl47/programming/TICPP-2nd-ed-Vol-one-html/Chapter11.html

J’ai le Kernighan et Ritchie comme livre de chevet, ça suffit peut-être pas…

XavierMiller: Mais es-tu sûr que voie2 != 0 ?

Oui puisqu'avec cette méthode :

  sprintf(wInfo.ligne0, "Rx: %04d ", voie1);
  sprintf(wInfo.ligne0, "%s%04d ", wInfo.ligne0, voie2);

J'obtiens des données cohérentes.

C’est du hasard, car tu écris dans un string qui est en cours de lecture ! Très dangereux car le comportement n’est pas défini.

Le dernier essai réalisé :

info recepteur::debug(){
  // Test : 
  info wInfo;
  char valStr[20];
  sprintf(valStr, "Rx: %04d %04d", voie1, voie2);
  memcpy(wInfo.ligne0, valStr, strlen(valStr)+1);
  sprintf(valStr, "    %04d %04d", voie3, voie4);
  memcpy(wInfo.ligne1, valStr, strlen(valStr)+1);
  return wInfo;
}

J'ai toujours le même résultat : Rx: 1504 0000

Pour moi, il ne sais pas mettre l'attribut voie2 à la place du dexième %04d

2 classes plus loin, j'ai le même type de traitement qui fonctionne correctement :

void voie::description(char * valStr){
  // Test : OK
  //sprintf(valStr, "%3s\n %04d %04d %04d", nom, rx_min, rx_neu, rx_max);
  sprintf(valStr, "%04d %04d %04d", rx_min, rx_neu, rx_max);
}

Je ne sais pas quoi faire!

Je viens d'essayer ça :

void recepteur::debug2(info* wInfo){
  // Test : 
  char valStr1[20];
  sprintf(valStr1, "Rx: %04d %04d", voie1, voie2);
  char valStr2[20];
  sprintf(valStr2, "Rx: %04d %04d", voie1, voie2);
  
  (*wInfo).affecter(valStr1, valStr2);
}

Avec la méthode :

void info::affecter(char const* wL0, char const* wL1){
  // Test : OK
  memcpy(ligne0, wL0, strlen(wL0)+1);
  memcpy(ligne1, wL1, strlen(wL1)+1);
}

C'est pas mieux! =(

Donc c'est bien ce que je pensais. Lis bien le chapitre que je t'ai donné en URL; il explique pourquoi ce que tu as fait ne fonctionnait pas : tout est perturbé parce que ta variable locale est dans la pile, qui se dépile durant le return. Tu tombes sur des zones mémoires qui ne sont plus allouées, et dans des zones dangereuses et aléatoires.

J'ai bien compris que le code écrit au départ n'était pas propre :

info recepteur::debug(){
  // Test : 
  info wInfo;
//  sprintf(wInfo.ligne0, "Rx: %04d %04d", voie1, voie2);
  sprintf(wInfo.ligne0, "Rx: %04d ", voie1);
  sprintf(wInfo.ligne0, "%s%04d ", wInfo.ligne0, voie2);
//  sprintf(wInfo.ligne1, "    %04d %04d", voie3, voie4);
  sprintf(wInfo.ligne1, "    %04d ", voie3);
  sprintf(wInfo.ligne1, "%s%04d ", wInfo.ligne1, voie4);
  return wInfo;
}

Maintenant, la fonction écrite avec le pointeur sur ma variable externe me semblait plus propre :

void recepteur::debug2(info* wInfo){
  // Test : 
  char valStr1[20];
  sprintf(valStr1, "Rx: %04d %04d", voie1, voie2);
  char valStr2[20];
  sprintf(valStr2, "Rx: %04d %04d", voie1, voie2);
  
  (*wInfo).affecter(valStr1, valStr2);
}
void info::affecter(char const* wL0, char const* wL1){
  // Test : OK
  memcpy(ligne0, wL0, strlen(wL0)+1);
  memcpy(ligne1, wL1, strlen(wL1)+1);
}
  recepteur rxNeutre;  // Donnée isuue du récepteur
  info wDebug;
  rxNeutre.voie1 = 1234;
  rxNeutre.voie2 = 4321;
  rxNeutre.voie3 = 5678;
  rxNeutre.voie4 = 9876;  

  rxNeutre.debug2(&wDebug);
  wDebug.affiche(currentLCD);

Toutes les variables utilisées dans les méthodes debug2(), affecter() et affiche() font références au variables principales. Tout se passe comme si voie2 (et voie4) n'existait pas? Or voie2, c'est l'objet sur lequel on travaille, c'est this.voie2, c'est rxNeutre.voie2 Je ne comprendrais pas pour quelle raison il serait détruit!!

Bref : pour dire que je ne vois absolument pas où faire une modification pour que cela fonctionne...

Après une bonne nuit de sommeil, j'ai sorti le code problématique pour le mettre dans le Setup (en dehors de toute classe), et voilà le résultat :

Ce code ne fonctionne pas :

  char valStr2[20];
  unsigned long V3 = 3456;
  unsigned long V4 = 7654;
  sprintf(valStr2, "Rx: %04d %04d", V3, V4);
  slcd.setCursor(0, 1);
  slcd.print(valStr2);

Celui-ci fonctionne :

  char valStr2[20];
  unsigned long V3 = 3456;
  unsigned long V4 = 7654;
  sprintf(valStr2, "Rx: %04d %04d", (int) V3, (int) V4);
  slcd.setCursor(0, 1);
  slcd.print(valStr2);

La méthode sprintf attend de l'integer pour fonctionner correctement.

Bernardino:
Celui-ci fonctionne :

  char valStr2[20];

unsigned long V3 = 3456;
  unsigned long V4 = 7654;
  sprintf(valStr2, “Rx: %04d %04d”, (int) V3, (int) V4);
  slcd.setCursor(0, 1);
  slcd.print(valStr2);




La méthode *sprintf* attend de l'integer pour fonctionner correctement.

Si printf attend un int pour fonctionner c’est parce que tu lui as dit que tu lui donnerai un int ! Donc soit tu fais une conversion de type comme dans ton deuxième exemple, soit tu utilise %04ld comme format (note le L minuscule avant le d). D’ailleurs le compilateur a dû émettre un avertissement pour te prévenir qu’il y avait un problème à ce niveau.

Sinon, question subsidiaire, est-il vraiment nécessaire d’utiliser un long si seuls les 4 premiers chiffres t’intéresses ?

question subsidiaire, est-il vraiment nécessaire d'utiliser un long si seuls les 4 premiers chiffres t'intéresses ?

Oui, j'ai besoin de cumuler des valeurs qui sont dans l'interval [900..2100]. Au bout de 31 valeurs, on arrive à la limite des unsigned int. C'est vrai que dans 99% des cas, je ne dépasserai pas les 2100 mais j'avais pas envie de créer une autre classe juste pour ça...

En tout cas, merci à tous d'avoir pris un peu de votre temps pour vous pencher sur mon problème. Merci à XavierMiller pour son lien sur le C++, j'ai effectivement quelques lacunes à combler! 20 ans sans programmation C, ça ne se rattrappe pas comme ça...

Olivier

Quoi qu'il en soit, tu auras des résultats tronqués si tu fais (int) (long) : tu risques d'avoir des surprises si ton long est > que le plus grand int.

On est bien d'accord. Le cas où j'ai besoin de cumuler ces valeurs est bien mairisé.