OVH Cloud OVH Cloud

Double -> string

11 réponses
Avatar
Fanny Chevalier
Comment concatener un double a une chaine de caractere ?

10 réponses

1 2
Avatar
Emmanuel Delahaye
In 'fr.comp.lang.c', Fanny Chevalier wrote:

Comment concatener un double a une chaine de caractere ?


Avec sprintf()

#include <stdio.h>
int main (void)
{
char s[128];

int n = sprintf (s, "%s", "hello world: ");

n += sprintf (s + n, "%f", 123.456);

puts(s);

return 0;
}

--
-ed- [remove YOURBRA before answering me]
The C-language FAQ: http://www.eskimo.com/~scs/C-faq/top.html
<blank line>
FAQ de f.c.l.c : http://www.isty-info.uvsq.fr/~rumeau/fclc/

Avatar
Emmanuel Delahaye
In 'fr.comp.lang.c', NACIRI Youssouf wrote:

#include <stdio.h>
...
double a;
char str[100];
...
sprintf(str, "%s %f", str, a);

Une chose a verifier, cette methode lit et ecrit en meme temps sur al
chaine str... C'est pas tres catholique...


En effet, on a pas le droit de faire ça. (Le résultat est indéterminé)

--
-ed- [remove YOURBRA before answering me]
The C-language FAQ: http://www.eskimo.com/~scs/C-faq/top.html
<blank line>
FAQ de f.c.l.c : http://www.isty-info.uvsq.fr/~rumeau/fclc/

Avatar
Emmanuel Delahaye
In 'fr.comp.lang.c', Rene Luria wrote:

Avec sprintf()


osé...

char s[128];


c'est la partie que je préfère

int n = sprintf (s, "%s", "hello world: ");
n += sprintf (s + n, "%f", 123.456);


Dans ton exemple bien précis, ça marche.


C'est le but!

Maintenant il demandait pour écrire "une" chaine et "un" double. Donc à
priori aucune indication sur la longueur de la chaine obtenue => le mal est
en toi.


Tu veux dire qu'il y a risque de débordement? Avec des données variables,
certes. J'aurais dû faire une petit rappel!

Maintenant c'est bien gentil de critiquer mais je suppose que prendre un
char [] taille fixe c'est pour éviter d'allouer à tout vent.


C'était surtout pour montrer une technique de base sans noyer le newbie sous
un flot d'informations.

Je proposerai peut-être ça:

#include <stdio.h>
#include <stdlib.h>
#define TAILLE_B 128
char *
ma_concat (char *chaine, double nombre)
{
char *output = xmalloc (TAILLE_B);


Là, je pense que le newbie a déjà pété les plombs, et qu'il pleure sa mère!

size_t longueur;
if ((longueur =
snprintf (output, TAILLE_B, "%s %f", chaine, nombre))
= TAILLE_B)



Est-tu bien sûr que snprintf() retourne le nombre de bytes théoriques? de
plus, je rappelle que tout le monde ne dispose pas de cette fonction (C99).

Et puis, j'évite de mélanger affectation et test quand je peux, ainsi que de
définir une variable sans initialisation, si celle-ci est évidente:

size_t longueur = snprintf (output, TAILLE_B, "%s %f", chaine, nombre);

if (longueur >= TAILLE_B)
{

Et voilà du code lisible, compréhensible et maintenable!

{
output = xrealloc (output, longueur + 1);
sprintf (output, "%s %f", chaine, nombre);
}
return output;
}

/* xmalloc et xrealloc définies par l'utilisateur, testant les retours des
malloc et realloc */


En ça fait quoi en quoi d'erreur? Un retour au système bien crade en laissant
la mémoire allouée et les fichiers ouverts? Pas de ça chez moi.

--
-ed- [remove YOURBRA before answering me]
The C-language FAQ: http://www.eskimo.com/~scs/C-faq/top.html
<blank line>
FAQ de f.c.l.c : http://www.isty-info.uvsq.fr/~rumeau/fclc/


Avatar
Emmanuel Delahaye
In 'fr.comp.lang.c', Rene Luria wrote:

if ((longueur >>> snprintf (output, TAILLE_B, "%s %f", chaine, nombre))
= TAILLE_B)



Est-tu bien sûr que snprintf() retourne le nombre de bytes théoriques? de
plus, je rappelle que tout le monde ne dispose pas de cette fonction
(C99).


En effet, c'est du C99.
Mais tu mets le doigt sur un problème évident. Selon l'implémentation, le


Comment ça évident?

retour change. Dans le monde des féées, avec une glibc pas trop trop
vieille, ça se comporte impec.


Que dit la norme?

7.19.6.5 The snprintf function

Synopsis
1 #include <stdio.h>
int snprintf(char * restrict s, size_t n,
const char * restrict format, ...);

Description
2 The snprintf function is equivalent to fprintf, except that the output
is written into an array (specified by argument s) rather than to a
stream. If n is zero, nothing is written, and s may be a null pointer.
Otherwise, output characters beyond the n-1st are discarded rather than
being written to the array, and a null character is written at the end
of the characters actually written into the array. If copying takes
place between objects that overlap, the behavior is undefined.

Returns
3 The snprintf function returns the number of characters that would have
been written had n been sufficiently large, not counting the terminating
null character, or a negative value if an encoding error occurred.
Thus, the null-terminated output has been completely written if and only
if the returned value is nonnegative and less than n.

Ok. Donc, ce que tu veux faire est correct.

Maintenant, avec une version qui le supporte mais plus anciennes, (de la
2.0.6 à la 2.1 [tiré d'un man]), il va retourner 0 si c'est tronqué.


C'est le problème des fonctions pré-ISO qui ressemblent à des fonctions ISO.
Très dangereux!

La question qui me vient à l'esprit, car ce n'est pas très clair, c'est que
dans ce cas, snprintf tronquet et ajoute un '' ? Comment connaitre la
longueur si ce n'est en tatonant ? (i.e. réallouant au fur et à mesure dans
une boucle)


Ce cas là n'étant pas standard, on s'en tape. Si j'ai bien compris, on peut
faire une "mesure" en mettant par exemple une taille de 1, ensuite on alloue
le bloc, puis on utilise le bloc alloué.
C'est pas mal!

char s_try[1]

size_t len = snprintf (s_try
, sizeof stry
, "%s : %.2f euros"
, "prix de l'article"
, 123.45);

char *s_out = malloc (len + 1);

if (s_out)
{
len = snprintf (s_out
, len + 1
, "%s : %.2f euros"
, "prix de l'article"
, 123.45);

printf ("%sn", s_out);
free (s_out);
}

Il y a intérêt à ce que les paramêtres variables soient strictement
identiques. Des variables locales peuvent aider la maintenance...

<...>

S'il veut faire ça un peu mieu, il fera un
return NULL;
ce qui est surement le plus probable puisque la fonction était censée
retourner un (char *)


C'est une macro alors? Parce que si c'est xalloc() qui retourne NULL, merci,
on avait déjà malloc()!

Et si c'est une macro qui fait un retour direct invisible, bonjour le debug
pour cause de sortie sauvage. Non, vraiment, je ne vois pas l'intéret de
changer la sémantique de ces fonctions.

--
-ed- [remove YOURBRA before answering me]
The C-language FAQ: http://www.eskimo.com/~scs/C-faq/top.html
<blank line>
FAQ de f.c.l.c : http://www.isty-info.uvsq.fr/~rumeau/fclc/




Avatar
Rene Luria
Que dit la norme?

7.19.6.5 The snprintf function


Décidément il faut que je perde l'habitude de ne lire que les pages de man
toujours si incomplètes d'un OS que je ne nomerai pas.
Merci pour le bout de norme, c'est tout de suite plus strict et clair.

C'est le problème des fonctions pré-ISO qui ressemblent à des fonctions
ISO. Très dangereux!


clair

Ce cas là n'étant pas standard, on s'en tape.


On peut toujours essayer...

Si j'ai bien compris, on
peut faire une "mesure" en mettant par exemple une taille de 1, ensuite on
alloue le bloc, puis on utilise le bloc alloué.
C'est pas mal!


J'ai du faire appel à ça dans un cas un peu particulier.
Une fonction prenant des paramètres variables, qui devait reformater la
chaine avant... peu importe le contexte, le but avoué était soit d'utiliser
un tableau de taille fixe, un char s_out[24] par exemple, et un char
*ps_out = s_out; histoire de minimiser les allocations dynamiques. Si la
chaine était trop grande, alors j'alouais sur un char *s_out_dyn; et je
pointais ls ps_out dessus.
Intéret, n'allouer que si la chaine est trop grande, tout en restant plus ou
moins transparent.

L'exemple que tu résumes après montre bien l'intéret du retour du snprintf
en effet.

char s_try[1]

size_t len = snprintf (s_try
, sizeof stry
, "%s : %.2f euros"
, "prix de l'article"
, 123.45);

char *s_out = malloc (len + 1);

if (s_out)
{
len = snprintf (s_out
, len + 1
, "%s : %.2f euros"
, "prix de l'article"
, 123.45);

printf ("%sn", s_out);
free (s_out);
}

S'il veut faire ça un peu mieu, il fera un
return NULL;
ce qui est surement le plus probable puisque la fonction était censée
retourner un (char *)


C'est une macro alors? Parce que si c'est xalloc() qui retourne NULL,
merci, on avait déjà malloc()!


Non, c'était une manière maladroite de simplement montrer qu'il fallait
prendre garde au retour de ces fonctions. Libre au dev de faire comme il
veut après, j'aurais du le préciser dès le début.

--
Rene Luria [0C205377]
fingerprint = 33E2 2E38 68CB 15F6 EAC8 E365 BE8A 41BB 0C20 5377


Avatar
Antoine Leca
Bonjour,

Rene Luria écrivit
Avec sprintf()


osé...


C'est pourtant ce pourquoi c'est fait (en utilisant "%.*g", DBL_DIG-1, x).


char s[128];


c'est la partie que je préfère


C'est vrai que c'est incorrect. Faisons donc un peu de théorie (au lieu
d'aller
chercher à allouer des blocs de 64 KB « au cas où »):
- la longueur de la chaîne "source" peut être obtenue par strlen(), voire
un sizeof si on a des informations sur sa provenance (le cas le plus
courant)
- la longueur maximum du double par DBL_DIG, log10(DBL_MAX_10_EXP), et 10
(le signe, la virgule, le "e±", le '' final, 1+1 pour les arrondis
et la sécurité)


int n = sprintf (s, "%s", "hello world: ");
n += sprintf (s + n, "%f", 123.456);



"%f" n'est pas génial dans l'absolu, parce que cela peut te générer des
tonnes de zéros non significatifs.
Par contre, c'est adapté si tu manipules des montants, et que l'on
t'obliges à travailler avec des doubles. Dans ce cas, tu as des
informations sur l'intervalle des montants, tu peux dimensionner
correctement : il suffit alors d'un assert() bien placé, testant aussi
bien les positifs que les négatifs!


Antoine


Avatar
Bertrand Mollinier Toublet
Antoine Leca wrote:
correctement : il suffit alors d'un assert() bien placé, testant aussi
bien les positifs que les négatifs!

Excusez-moi pour le bruit, mais: Antoine, tu voudrais pas configurer ton

client news correctement (ou alternativement m'expliquer en quoi il est
correctement configure...) et choisir un charset decent. Tous tes
caracteres accentues apparaissent comme des ? et c'est encore plus
illisible que moi qui shunte les accents.

Vu dans le source de ton post:

Content-Type: text/plain;
charset="x-user-defined"
^^^^^^^^^^^^^^
Mmmmmh... ca serait pas mieux ISO-8859-1, ou quelque chose comme ca ?
--
Bertrand Mollinier Toublet
"Reality exists" - Richard Heathfield, 1 July 2003

Avatar
Claudio
On Wed, 9 Jul 2003, Fanny Chevalier wrote:


Comment concatener un double a une chaine de caractere ?





#include <stdio.h>

...

double a;
char str[100];

...

sprintf(str, "%s %f", str, a);


Une chose a verifier, cette methode lit et ecrit en meme temps sur al
chaine str... C'est pas tres catholique...

Autre methode plus complexe :

#include <stdio.h>
#include <string.h>

...

double a;
char str1[100], str2[100];

...

sprintf(str2, "%f", a);
strcat(str1, str2);


Voila


Divide ut regnes.
Divise afin de regner

Youssouf

La deuxième méthode me semble correcte, à condition de rajouter un test

sur les longueurs des chaines str1 et str2 (fonction strlen()) avant la
concaténation !
Ou alors utiliser strncat(), avec précision de la longueur maximale de
la chaine résultante


Avatar
Antoine Leca
Je vous prie vraiment de m'excuser :o(. Cette fois-ci ce devrait être
mieux...

Bertrand Mollinier Toublet écrivit:
Excusez-moi pour le bruit, mais: Antoine, tu voudrais pas configurer ton
client news correctement


Hmmm.... Désolé, j'ai oublié de "repasser" le message en encodage standard.
(Je compose en encodage "user-defined", seule manière simple que j'ai trouvé
de pouvoir couper les lignes au bon endroit avec ce @#! de client qui pense
savoir mieux que moi ce que je veux envoyer; et là j'ai oublié de repasser
en Latin-[19], ce que je fait d'habitude).


Antoine

Avatar
Bertrand Mollinier Toublet
Antoine Leca wrote:
Je vous prie vraiment de m'excuser :o(. Cette fois-ci ce devrait être
mieux...

Bertrand Mollinier Toublet écrivit:

Excusez-moi pour le bruit, mais: Antoine, tu voudrais pas configurer ton
client news correctement



Hmmm.... Désolé, j'ai oublié de "repasser" le message en encodage standard.
(Je compose en encodage "user-defined", seule manière simple que j'ai trouvé
de pouvoir couper les lignes au bon endroit avec ce @#! de client qui pense
savoir mieux que moi ce que je veux envoyer; et là j'ai oublié de repasser
en Latin-[19], ce que je fait d'habitude).


Pas de probleme. Pour le coup, tu piques ma curiosite. En quoi

l'encodage user-defined te permet-il de couper les lignes ou tu veux
(sous OE, si je ne m'abuse...) ? C'est un plugin ?


--
Bertrand Mollinier Toublet
"Reality exists" - Richard Heathfield, 1 July 2003


1 2