OVH Cloud OVH Cloud

Probleme avec scanf

118 réponses
Avatar
Bakounine
bonjour

je suis en train de faire un petit programme client et serveur qui echange
des messages. Dans cetains messages il y a deux valeur separer par des deux
points.

ex:

valeurun:valeurdeux

j'aimerais savoir si sscanf permet de gerer le separateur : ou faut il
utiliser une autre fonction? j'ai utilise sscanf("%s:%s", var1, var2); mais
ca ne marche pas.

Merci d'avance pour votre reponse.

10 réponses

1 2 3 4 5
Avatar
Richard Delorme
Richard Delorme wrote on 25/04/05 :

sscanf(msg, "[^:]:%s", var1, var2);



Marche pas...


désolé, un % un sauté.

sscanf(msg, "%[^:]:%s", var1, var2);


--
Richard


Avatar
Harpo
Bakounine wrote:


Merci c parfait je vais utiliser ca. Mais si quelqu'un a la solution
avec le sscanf qu'il n'esite pas.


Avec le scanf, la meilleure solution est radicale : ne jamais
l'utiliser !
C'est trop merdique, utiliser les fonctions strxxx.

Avatar
Antoine Leca
Richard Delorme wrote:
sscanf(msg, "%[^:]:%s", var1, var2);


Pas cohérent: var1 peut contenir un espace, mais pas var2


Antoine

Avatar
AG
Antoine Leca à voulu dire :
Richard Delorme wrote:

sscanf(msg, "%[^:]:%s", var1, var2);



C'est effectivement la bonne solution, et si l'on veut pouvoir accepter

des espaces dans var 1
ET var2, ou aurait pu mettre :
sscanf(msg, "%[^:]:[^]",var1,var2);


Antoine
Alexandre, qui se couchera moins con ce soir.



Avatar
Antoine Leca
AG wrote:
Antoine Leca à voulu dire :


Tu te compliques la vie: sans accent c'est mieux!

Richard Delorme wrote:

sscanf(msg, "%[^:]:%s", var1, var2);


C'est effectivement la bonne solution,



« Bonne solution » est peut-être un peu fort, surtout quand on ne contrôle
pas ce que retourne sscanf (essaye avec un : en début ou fin de ligne), ni
la taille des tampons.

Quant à l'utiliser pour un TP, c'est nul: strchr ou strcspn/strpbrk(...,
":n") font bien mieux l'affaire. Voire strtok. ÀMHA.


et si l'on veut pouvoir
accepter des espaces dans var 1
ET var2, ou aurait pu mettre :
sscanf(msg, "%[^:]:[^]",var1,var2);


Suis-je censé compter les erreurs ? ;-)

Ou bien y a-t'il un souriard qui m'a échappé ?
(avec les yeux :, les nez en trompette ^ et les gueules de bois ], c'est
fort possible).



Antoine (qui doit appuyer sur *deux* touches pour fabriquer un à)



Avatar
Richard Delorme
AG wrote:

Antoine Leca à voulu dire :



Tu te compliques la vie: sans accent c'est mieux!


Richard Delorme wrote:


sscanf(msg, "%[^:]:%s", var1, var2);


C'est effectivement la bonne solution,




« Bonne solution » est peut-être un peu fort, surtout quand on ne contrôle
pas ce que retourne sscanf (essaye avec un : en début ou fin de ligne), ni
la taille des tampons.


Quand on ne connait pas le problème dans toutes ses largeurs, il est
difficile de savoir quelle est la bonne solution.

Quant à l'utiliser pour un TP, c'est nul: strchr ou strcspn/strpbrk(...,
":n") font bien mieux l'affaire. Voire strtok. ÀMHA.


Sans doute, mais il y a 9 chances sur 10 que la solution finale soit
encore plus foireuse, à mon avis tout aussi humble.

--
Richard




Avatar
Charlie Gordon
"Harpo" wrote in message
news:426d7f6c$0$25019$
Bakounine wrote:


Merci c parfait je vais utiliser ca. Mais si quelqu'un a la solution
avec le sscanf qu'il n'esite pas.


Avec le scanf, la meilleure solution est radicale : ne jamais
l'utiliser !


Tout à fait d'accord !

C'est trop merdique, utiliser les fonctions strxxx.


Sauf bien sûr strncpy, strncat et strtok qui ont leur propre lot de problèmes
merdiques.

Chqrlie.


Avatar
Charlie Gordon
"Richard Delorme" wrote in message
news:426e333d$0$21144$
AG wrote:
Antoine Leca à voulu dire :
Tu te compliques la vie: sans accent c'est mieux!

Richard Delorme wrote:
sscanf(msg, "%[^:]:%s", var1, var2);


C'est effectivement la bonne solution,



« Bonne solution » est peut-être un peu fort, surtout quand on ne contrôle
pas ce que retourne sscanf (essaye avec un : en début ou fin de ligne), ni
la taille des tampons.


Quand on ne connait pas le problème dans toutes ses largeurs, il est
difficile de savoir quelle est la bonne solution.

Quant à l'utiliser pour un TP, c'est nul: strchr ou strcspn/strpbrk(...,
":n") font bien mieux l'affaire. Voire strtok. ÀMHA.


Sans doute, mais il y a 9 chances sur 10 que la solution finale soit
encore plus foireuse, à mon avis tout aussi humble.


Bien sûr il manquait encore un %...
Mais notez bien que la ligne

sscanf(msg, "%[^:]:%[^:]", var1, var2);

ne vérifie aucunement que les parties de msg de part et d'autre du ':'
"tiennent" dans var1 et var2.
Il serait bien préférable de préciser la taille des tableaux var1 et var2 pour
éviter un débordement potentiel qui pourrait créer une faille de sécurité ou un
quelconque autre comportement indéfini. Malheureusement la syntaxe de sscanf ne
permet pas de préciser la taille des tableaux de char que explicitement dans la
chaine de format, et avec un nombre qui n'est pas sizeof(var1) !
Donc si les tableaux var1 ou var2 changent de taille ou sont d'une taille
variable ou paramétrique, ca devient particulièrement acrobatique puisqu'il faut
fabriquer la chaine de sscanf() avec printf(), ce qui empêche d'ailleurs le
compilateur de faire des vérifications simples de cohérence entre la chaine de
format de sscanf() et les paramètres qui lui sont passés.
La seule solution dans le cas présent consiste à dimensionner var1 et var2 à la
même taille que msg... Mais cette taille n'est pas connue à compile time...
Enfin autre problème : le résultat de sscanf() permet de savoir combien de
champs ont été traités, ou si une erreur s'est produite.
Comme ce résultat n'est pas stocké, on ne peut pas savoir ce qui s'est
réellement passé, et le contenu de var1 et var2 est potentiellement quelconque,
donc même en mesurer la taille avec strlen() peut déclencher un comportement
indéfini.

Conclusion : NE PAS UTILISER SCANF !

Chqrlie.





Avatar
Targeur fou
Charlie Gordon wrote:
"Richard Delorme" wrote in message
news:426e333d$0$21144$
AG wrote:
Antoine Leca à voulu dire :
Tu te compliques la vie: sans accent c'est mieux!

Richard Delorme wrote:
sscanf(msg, "%[^:]:%s", var1, var2);


C'est effectivement la bonne solution,



« Bonne solution » est peut-être un peu fort, surtout quand on
ne contrôle



pas ce que retourne sscanf (essaye avec un : en début ou fin de
ligne), ni



la taille des tampons.


Quand on ne connait pas le problème dans toutes ses largeurs, il
est


difficile de savoir quelle est la bonne solution.

Quant à l'utiliser pour un TP, c'est nul: strchr ou
strcspn/strpbrk(...,



":n") font bien mieux l'affaire. Voire strtok. ÀMHA.


Sans doute, mais il y a 9 chances sur 10 que la solution finale
soit


encore plus foireuse, à mon avis tout aussi humble.


Bien sûr il manquait encore un %...
Mais notez bien que la ligne

sscanf(msg, "%[^:]:%[^:]", var1, var2);

ne vérifie aucunement que les parties de msg de part et d'autre du
':'

"tiennent" dans var1 et var2.
Il serait bien préférable de préciser la taille des tableaux var1
et var2 pour

éviter un débordement potentiel qui pourrait créer une faille de
sécurité ou un

quelconque autre comportement indéfini. Malheureusement la syntaxe
de sscanf ne

permet pas de préciser la taille des tableaux de char que
explicitement dans la

chaine de format, et avec un nombre qui n'est pas sizeof(var1) !
Donc si les tableaux var1 ou var2 changent de taille ou sont d'une
taille

variable ou paramétrique, ca devient particulièrement acrobatique
puisqu'il faut

fabriquer la chaine de sscanf() avec printf(), ce qui empêche
d'ailleurs le

compilateur de faire des vérifications simples de cohérence entre
la chaine de

format de sscanf() et les paramètres qui lui sont passés.
La seule solution dans le cas présent consiste à dimensionner var1
et var2 à la

même taille que msg... Mais cette taille n'est pas connue à
compile time...

Enfin autre problème : le résultat de sscanf() permet de savoir
combien de

champs ont été traités, ou si une erreur s'est produite.
Comme ce résultat n'est pas stocké, on ne peut pas savoir ce qui
s'est

réellement passé, et le contenu de var1 et var2 est potentiellement
quelconque,

donc même en mesurer la taille avec strlen() peut déclencher un
comportement

indéfini.

Conclusion : NE PAS UTILISER SCANF !


Il est où le problème avec scanf ? ;-) Dans ce qui suit, quelle est
la différence avec fgets() d'un point de vue pratique par exemple ?

#include <stdio.h>

#define LG_SAISIE_STDIN 20
#define STR_(s) #s
#define STR(s) STR_(s)

int main(void)
{
int rc;
char tamponSaisie[LG_SAISIE_STDIN+1] = { '' };

rc = scanf("%"STR(LG_SAISIE_STDIN)"[^n]%*[^n]",tamponSaisie);
getchar();
if (rc != EOF) {
printf("Donnees saisies : n%sn", tamponSaisie);
}
else {
puts("Erreur lors de la saisie");
}

return 0;
}

Regis






Avatar
Antoine Leca
Charlie Gordon écrivit dans news:d4nkco$ma3$
Mais notez bien que la ligne

sscanf(msg, "%[^:]:%[^:]", var1, var2);


Attention aux n qui traînent en «fin» de msg: ils auraient été un butoir
pour %s, mais %[^n] va passer outre, ce qui peut être un souci.


ne vérifie aucunement que les parties de msg de part et d'autre du ':'
"tiennent" dans var1 et var2.
Il serait bien préférable de préciser la taille des tableaux var1 et var2
pour

éviter un débordement potentiel qui pourrait créer une faille de sécurité
ou un

quelconque autre comportement indéfini.


Pas sûr.
Le contrôle de taille se fait avant, au niveau de l'acquisition de msg. Si
tu as dimensionné var1 et var2 de la même taille que msg, je ne vois pas
comment tu peux avoir un débordement, sauf en présence de bogue dans
l'implémentation de sscanf.


Maintenant, si tu es obligé (par circonstance extérieure) d'avoir une taille
donnée pour var1 ou var2 (inférieure à celle de msg), il faut effectivement
imposer des limites:

#define ch(x) cx(x) /* truc horrible pour convertir la valeur */
#define cx(x) #x /* d'une constante en morceau de chaîne */

char var1[TAILLE_DE_VAR1], var2[TAILLE_DE_VAR2];

if( 2 != sscanf(msg, "%" ch(TAILLE_DE_VAR1) "[^:]:"
"%" ch(TAILLE_DE_VAR2) "[^:]",
var1, var2) ) /*...*/

ce qui renforce les raisons de vérifier la valeur retournée (à quoi sert de
poser des limites si elles ne sont pas vérifiées ?)


Conclusion : NE PAS UTILISER SCANF !


Dommage. ;-)



Antoine (qui se *précipite* sur strtok() pour faire ce genre de découpage
:-)) )

1 2 3 4 5