[Résolu] Integer en String

Bonsoir,
Après une longue bataille au corps à corps et à l’arme blanche pour écrire une fonction qui convertisse un integer en une chaîne de caractères pour un affichage sur un écran lcd de 4 lignes de 20 caractères sous I2C (LCD03).
Le programme joint au topic réalise cette conversion et me donne le résultat souhaité. Ouff
Par contre j’ai 3 questions liées oui induites par l’écriture de cette fonction IntegerToString(), à savoir :

  1. Etant débutant en C, j’aimerai savoir si le programme respecte les “us et coutumes” ou “standard” de C,
  2. Je n’ai pas réussi à traiter le dépassement des plages de validité des Integer. C’est à dire si l’entrée est inférieure à -32768 ou si supérieure à +32767.
    lorsqu’on entre un nombre inférieur à -32768 on a la transmission d’une valeur de +32000 et des poussières et si l’on entre un nombre supérieur à +32767 on a une
    valeur transmisse de -32000 et des broutilles .
    En attendant de trouver une solution j’ai limité la plages d’entrée des nombres entre -32000 et +32000.
  3. Est-il possible de lancer automatiquement le moniteur série de l’EDI Arduino ?
/*
Programme : Traitement des Strings
création : 24/05/2012 - mise à jour : 25/05/2012
version  : 1.0
auteur   : Patrice Seibel alias icare petibles
support  : icare.petibles@orange.fr
matériel : Arduino Duemilanove

Le programme convertit une entrée de type INTEGER (16 bits)en chaîne de caractères de type 
STRING au format décimal, hexadécimal ou binaire suivant la demande lors de l'appel de la 
fonction IntegerToString(Valeur,"format"))
*/
//*************************************************************************************
//Directives
//*************************************************************************************
#include <Wire.h>										//Utilisation de la bibliothèque I2C
#include <LCD03.h>										//Utilisation de la bibliothèque LCD03

//*************************************************************************************
//Délarations des variables et constantes
//*************************************************************************************
LCD03 lcd;												//Afficheur utilisé LCD03 avec l'adresse par défaut

char *resultat = "";										//Variable
int longueur = 0;											//Variable longueur string convertit

//*************************************************************************************
//Initialisation
//*************************************************************************************
void setup()	{
	int const PAUSE = 5000;								//Durée pause
	int entree = 0;										//Données à convertir
	Serial.begin(9600);									//Initialisation com série
	Serial.println("Arduino");								//Message
	Serial.println("Conversion INTEGER en STRING");
	lcd.Cls();											//Efface écran
  delay(1000);											//Attente de confort
	lcd.CurOff();										//Curseur invisible
  lcd.BacklightOn();										//Allume le backlight 
													//Message d'acceuil
//	lcd.superPrint(1,1,"   Programme de");
//	lcd.superPrint(1,2,"    conversion");
//	lcd.superPrint(1,3," nombres en string");
//	lcd.superPrint(18,4,"psl");
//	delay(PAUSE);										//Attente
//	lcd.Cls();											//Efface écran
	//Test affichage sur afficheur LCD03
	entree = 1;
	strcpy(resultat,IntegerToString(entree,"bin"));
	lcd.superPrint(1,1,(resultat));
	strcpy(resultat,IntegerToString(15,"bin"));
	lcd.superPrint(1,2,(resultat));
	strcpy(resultat,IntegerToString(255,"bin"));
	lcd.superPrint(1,3,(resultat));
	strcpy(resultat,IntegerToString(4095,"bin"));
	lcd.superPrint(1,4,(resultat));
	
	delay(PAUSE);
	
	//Test affichage sur moniteur série
	strcpy(resultat,IntegerToString(entree,"bin"));
	Serial.print(entree);
	Serial.print("      -> ");
	Serial.println(resultat);
	strcpy(resultat,IntegerToString(15,"bin"));
	Serial.print(15);
	Serial.print("     -> ");
	Serial.println(resultat);
	strcpy(resultat,IntegerToString(255,"bin"));
	Serial.print(255);
	Serial.print("    -> ");
	Serial.println(resultat);
	strcpy(resultat,IntegerToString(4095,"bin"));
	Serial.print(4095);
	Serial.print("   -> ");
	Serial.println(resultat);
	strcpy(resultat,IntegerToString(31999,"bin"));
	Serial.print(31999);
	Serial.print("  -> ");
	Serial.println(resultat);
	strcpy(resultat,IntegerToString(-31999,"bin"));
	Serial.print(-31999);
	Serial.print(" -> ");
	Serial.println(resultat);
}

//*************************************************************************************
//Boucle sans fin
//*************************************************************************************
void loop()	{
//Ne fait pas grand chose, mais je tourne en rond
}
//*************************************************************************************
//Fonctions
//*************************************************************************************
//
//Fontion conversion d'un integer en string
//
char *IntegerToString(int Valeur, char *Base)	{
	char *f_texte = "";									//Résultat de la conversion
	byte f_base = 0;										//Base dec, hex ou bin
	char f_prov1[3] = "";									//Entête bin et hex
	char f_prov2[40] = "";									//Chaine 
	char c;											//
	if ((Valeur > -32000) && (Valeur < 32000)) {	                                //Reste à régler le dépassement
		//Début dec
		if ((Base == "DEC") || (Base == "dec") || (Base == "Dec")) {
				f_base = 10;							//Base 10 - décimal
				strcpy(f_prov1,"");						//Pas de signe distinctif
			}	
		//Fin dec
			else
			{
			//Début hex
				if ((Base == "HEX") || (Base == "hex") || (Base == "Hex")) {
					f_base = 16;						//Base 16 - hexadécimal
					strcpy(f_prov1,"0x");					//0x
					if (Valeur >= 0)	{					//Valeurs positives
						if ((Valeur >= 0) && (Valeur <= 15))	{
							strcat(f_prov1,"000");			//Ajoute 3 zéros
						}
						else if ((Valeur >15) && (Valeur <= 255))	{
							strcat(f_prov1,"00");			//Ajoute 2 zéros
						}
						else if ((Valeur >255) && (Valeur <= 4095))	{
							strcat(f_prov1,"0");			//Ajoute 1 zéro
						}
					}
				}
				//Fin hex
				else
				{
				//Début bin
					if ((Base == "BIN") || (Base == "bin") || (Base == "Bin")) {
						f_base = 2;						//Base 2 - binaire
						strcpy(f_prov1,"0b");				//0b
						if (Valeur >= 0)	{				//Valeurs positives
							itoa(Valeur,f_prov2,f_base);		//Convertit Valeur en string
							longueur = strlen(f_prov2);		//Longueur de Valeur en string
													//Rajoute les 0 manquant
							for (unsigned i = 0; i < (16 - longueur); i++) 
								strcat(f_prov1,"0");		//Copie 0 dans la variable
						}							//Fin valeurs positives
						else							//Valeurs négatives
						{
						// A compléter
						}							//Fin valeurs négatives
					}								//Fin bin
					else								//Début par défaut
					{
						f_base = 10;					//Base 10 - décimal - Valeur par défaut
						strcpy(f_prov1,"");				//Pas de signe distinctif
					}								//Fin défaut
				}
			}
			//Traitement
			strcpy(f_texte,f_prov1);						//Copie en-tête pour hex et bin
			itoa(Valeur,f_prov2,f_base);						//Convertit Valeur en string
													//Conversion minuscule majuscule
			for (unsigned i = 0; f_prov2[i] != '\0'; i++)
				f_prov2[i] = toupper(f_prov2[i]);				//Convertit en majuscule si possible
				
			strcat(f_texte,f_prov2);						//Complète avec Valeur en string
	}
	else
	{
		strcpy(f_texte,"ERROR");							//Hors plage de conversion
	}
	return f_texte;										//Retourne le résultat de la conversion
}

Merci pour vos précisions.
Icare

pour convertir un integer en string il faut utiliser sprintf

sprintf(chaineDest, "%d", tonInteger);

(c'est la version C)

je pense qu'en utilisant le C++ tu dois avoir accès à une méthode genre monInteger.String()

Salut,

+1 avec Vohu, la fonction sprintf (ou snprintf) fait exactement ce que tu veux...

Concernant ta fonction, deux choses me sautent aux yeux :

char *IntegerToString(int Valeur, char *Base)   {
    char *f_texte = "";

        // ...

    return f_texte;                                     //Retourne le résultat de la conversion
}
  • Elle retourne un pointeur local à la fonction. Il y a de grandes chances que ça ne fonctionne pas car une fois sorti de cette fonction, le pointeur n'existe plus même s'il peut persister en mémoire. Il est préférable que ce soit la fonction appelante qui déclare le pointeur et qui le passe en argument à la fonction IntegerToString.

  • Pour lui indiquer la base, il faut lui passer une chaîne de caractères. ça fonctionne, mais je t'invite à jeter un oeil aux énumérations :

typedef enum bases
{
    bin,
    dec,
    hex
} base_t;

void IntegerToString(int Valeur, base_t base, char* f_texte)
{
    switch (base)
    {
        case bin:
            // Conversion en binaire.
        break;
        case dec:
            // Conversion en décimal.
        break;
        case hex:
            // Conversion en hexadécimal.
        break;
        default:
        break;
    }
}

++

Bonjour vohu et merci pour ton aide,

vohu: pour convertir un integer en string il faut utiliser sprintf sprintf(chaineDest, "%d", tonInteger); (c'est la version C)

Je vais explorer cette piste

vohu: je pense qu'en utilisant le C++ tu dois avoir accès à une méthode genre monInteger.String()

Alors pour cette partie je dois reconnaître très humblement que le chinois est plus facile pour moi :grin: Icare

Salut SesechXP et merci pour tes remarques,

SesechXP: Salut, +1 avec Vohu, la fonction sprintf (ou snprintf) fait exactement ce que tu veux... - Pour lui indiquer la base, il faut lui passer une chaîne de caractères. ça fonctionne, mais je t'invite à jeter un oeil aux énumérations :

typedef enum bases
{
    bin,
    dec,
    hex
} base_t;

void IntegerToString(int Valeur, base_t base, char* f_texte) {    switch (base)    {        case bin:            // Conversion en binaire.        break;        case dec:            // Conversion en décimal.        break;        case hex:            // Conversion en hexadécimal.        break;        default:        break;    } }



++

Je suis entrain de voir les possibilités de cette fonction !

Par contre pour la partie ci-dessous, j'aimerai des compléments si cela est possible

SesechXP: Concernant ta fonction, deux choses me sautent aux yeux :

void IntegerToString(int Valeur, base_t base, char* f_texte)
{
    switch (base)
    {
        case bin:
            // Conversion en binaire.
        break;
        case dec:
            // Conversion en décimal.
        break;
        case hex:
            // Conversion en hexadécimal.
        break;
        default:
        break;
    }
}
  • Elle retourne un pointeur local à la fonction. Il y a de grandes chances que ça ne fonctionne pas car une fois sorti de cette fonction, le pointeur n'existe plus même s'il peut persister en mémoire. Il est préférable que ce soit la fonction appelante qui déclare le pointeur et qui le passe en argument à la fonction IntegerToStrin

Dans la structure que tu proposes le résultat du traitement se retrouve dans les paramètres d'appel de la fonction dont on met le résultat dans une variable globale Ce type de structure n'est-elle pas un peu contraire à l'esprit des fonctions ? La structure que j'ai utilisé est-elle non utilisable ou bien existe-il une approche similaire mais fiable ?

@+ Icare

tiens, tu as les détails ici :slight_smile:

http://cpp.developpez.com/faq/cpp/?page=strings#STRINGS_numtostr

SInon, ce que veut dire SesechXP, c’est que lorsque tu envoies par Copie un pointeur à une fonction, toute modification de ce pointeur est perdue quand tu quittes la fonction. Si tu veux garder les modifications apportées, il faut envoyer l’adresse du pointeur à ta fonction en utilisant un double pointeur.

Etant donné que le prototype de ta fonction est : char *IntegerToString(int Valeur, char *Base) elle va retourner un pointeur.
MAIS… si le return renvoie un pointeur qui a été créé dans ta fonction, il sera libéré, et l’adresse renvoyée ne sera plus valide.
Le problème, c’est qu’en faisant ça, la plupart du temps ça marche quand même par chance , car il est peut probable qu’entre le moment ou tu quittes ta fonction, et ou tu récupères l’info dans la ligne qui appelait ta fonction, que quelque chose ait écrit à cet endroit.

Donc, il vaut mieux envoyer l’adresse d’un pointeur en parametre de fonction.

icare: Dans la structure que tu proposes le résultat du traitement se retrouve dans les paramètres d'appel de la fonction dont on met le résultat dans une variable globale Ce type de structure n'est-elle pas un peu contraire à l'esprit des fonctions ?

Une fonction doit surtout se limiter à effectuer une tâche précise, ici la conversion d'un entier en chaîne de caractères. Le passage du pointeur sur la chaîne de caractères est un moyen fiable de la remplir, justement sans recourir à une variable globale.

Au passage, il faut limiter au maximum le recours à des variables globales. D'ailleurs ta variable resultat pourrait (devrait selon moi) être interne à la fonction setup, de même que la variable longueur pour la fonction loop.

icare: La structure que j'ai utilisé est-elle non utilisable ou bien existe-il une approche similaire mais fiable ?

En restant proche de ton idée de départ, je pense à quelque chose dans ce genre :

void setup()
{
    int entree = 0;

    char texte[8] = { '\0' }; // Adapter la taille en fonction des valeurs max à convertir.
    IntegerToString(entree, bin, texte);
}

void IntegerToString(int Valeur, base_t base, char* f_texte)
{
    // Remplissage de la chaîne.
}

vohu: Le problème, c'est qu'en faisant ça, la plupart du temps ça marche quand même [u]par chance[/u] , car il est peut probable qu'entre le moment ou tu quittes ta fonction, et ou tu récupères l'info dans la ligne qui appelait ta fonction, que quelque chose ait écrit à cet endroit.

Selon la loi de Murphy, "If anything can go wrong, it will." XD

Oui :p C'est tout à fait ça :p

Tu n'a pas compris le fonctionnement de la mémoire et des pointeurs. Va jeter un coup d'oeil approfondi sur le tuto d'Osaka ou sur d'autre. A aucun moment tu alloue de la mémoire pour ta chaîne de résultat. Tu pars de f_texte = "" qui a alloué 1une chaîne de 1 caractère quelque par en mémoire et après tu continue a écrire allègrement derrière ce caractère dans de la mémoire qui est peut-être utilisée par quelque d'autre.

Aux suggestions ci-dessus d'allouer l'espace mémoire avant la fonction, j'ajoute qu'il faut aussi passer la longueur et vérifier que tu ne sort pas de l'espace mémoire alloué.

Une fonction comme strcpy() par example n'est pas sûre. Elle ne contrôle pas que l'espace mémoire de destination est suffisant pour copier la chaîne source. Lui préférer char * strncpy ( char * destination, const char * source, size_t num ); Au fur et a mesure que tu construis ta chaîne résultat tu dois savoir combien de caractère il te reste, sans oublier le caractère \0 final.

Sinon, pour une simple conversion entier vers caractères, itoa() est plus performant que sprintf().

Merci à tous les 3 pour vos conseils et remarques. Je repars à mes études. :stuck_out_tongue_closed_eyes: A bientôt si ma tête n'explose pas :P Icare

Meuh non, ne vas pas juste pas trop près du soleil, pour pas faire fondre tes ailes :stuck_out_tongue:

Quoi que… c’est pas le soleil de moselle qui risque de faire fondre quoi que ce soit en ce moment…

Bonsoir, Voilà tout arrive, il suffit de s'y mettre. Après étude du tuto d'Osaka sur les pointeurs, je devrais pouvoir écrire ma fonction de façon plus "fiable". On verra plus tard Icare