OVH Cloud OVH Cloud

va_start, va_end

16 réponses
Avatar
Frédéri MIAILLE
Bonjour,
dans le formatage d'une chaîne de caractère en utilisant une fonction à
liste d'arguments variable, je me demande s'il est possible de trouver la
taille resultante de la chaine de caractère avant, bien évidemment, de la
formater...

inline char *Parse(unsigned int _OutputSize, const char *_ToParse, ...) //
Je voudrais me débarrasser de _OutputSize.
{
if(!_ToParse)
return NULL;
char *Str=malloc(_OutputSize+1); // Dans les exemples existants,
"_OutputSize" est souvent une constante.
if(!Str)
;
va_list ArgPtr;
va_start(ArgPtr, _ToParse);
vsprintf(Str, _ToParse, ArgPtr);
va_end(ArgPtr);
Str[_OutputSize]='\0';
return Str;
}

Sinon question :
si je fais
void *NextArg=_ToParse;
NextArg=NextArg+1; // Là, je met bien la main sur le premier argument
facultatif suivant ?
NextArg=NextArg+1; // Et là, je passe bien au suivant ?
J'ai juste ?
Quelle que soit la plate-forme, ceci est toujours valable ?

Merci de vos lumières.
--
Frédéri MIAILLE
fr.comp.lang.c
fr.comp.lang.c++
fr.comp.os.ms-windows.programmation
fr.comp.graphisme.programmation

10 réponses

1 2
Avatar
Al 1
Frédéri MIAILLE a écrit:
Bonjour,
dans le formatage d'une chaîne de caractère en utilisant une foncti on à
liste d'arguments variable, je me demande s'il est possible de trouver la
taille resultante de la chaine de caractère avant, bien évidemment, de la
formater...

inline char *Parse(unsigned int _OutputSize, const char *_ToParse, ...) //
Je voudrais me débarrasser de _OutputSize.
{
if(!_ToParse)
return NULL;
char *Str=malloc(_OutputSize+1); // Dans les exemples existants,
"_OutputSize" est souvent une constante.
if(!Str)
;
va_list ArgPtr;
va_start(ArgPtr, _ToParse);
vsprintf(Str, _ToParse, ArgPtr);
va_end(ArgPtr);
Str[_OutputSize]='';
return Str;
}


typiquement, _OutputSize ne sert à rien, puisque
* soit le format obtenu dépasse _OutputSize, auquel cas on a un
dépassement de buffer dans vsnprintf
* soit le format obtenu ne dépasse pas _OutputSize, auquel cas la ligne
ne sert à rien

On peut donc se débarasser de _OutputSize sans changer le comportement.



Sinon question :
si je fais
void *NextArg=_ToParse;
NextArg=NextArg+1; // Là, je met bien la main sur le premier argume nt
facultatif suivant ?


NON

NextArg=NextArg+1; // Et là, je passe bien au suivant ?


NON

ça marchouille un peu avec un pécé pour plusieurs raisons, en
particulier parce que sizeof (int) == sizeof (void *), et parce que p our
un passage d'arguments variables, les char et short sont promus en
double.

essaie donc de passer un 'double' dans tes arguments pour voir !

Avatar
Frédéri MIAILLE
typiquement, _OutputSize ne sert à rien, puisque
* soit le format obtenu dépasse _OutputSize, auquel cas on a un
dépassement de buffer dans vsnprintf
C'est bien là le problème.


* soit le format obtenu ne dépasse pas _OutputSize, auquel cas la ligne
ne sert à rien
Donc "_ToParse" doit avoir la capacité de taille suffisante lors de la

reception de la chaine.
Un strlen(_ToParse) serait donc fortuit.

On peut donc se débarasser de _OutputSize sans changer le comportement.
Vraiment ?

Honnêtement, je ne comprend pas. Il faut bien un buffer capable de reçevoir
non seulement la taille de la chaine non formatée mais encore la taille
supplémentaire que la conversion des symboles implique ?

Dans tous les cas, si j'enlève mon OutputSize et que je met
strlen(_ToParse)+1 pour mon malloc ça plante.
Et ceci ne fonctionne pas :
Parse("Phrase : %s, %d", ChaineDeCharDe1000000, Nombre)
Tu vois ce que je veux dire.

Merci pour la réponse en tout cas.

--
Frédéri MIAILLE
fr.comp.lang.c
fr.comp.lang.c++
fr.comp.os.ms-windows.programmation
fr.comp.graphisme.programmation

Avatar
Yves ROMAN

Bonjour,
dans le formatage d'une chaîne de caractère en utilisant une fonction à
liste d'arguments variable, je me demande s'il est possible de trouver la
taille resultante de la chaine de caractère avant, bien évidemment, de la
formater...

inline char *Parse(unsigned int _OutputSize, const char *_ToParse, ...) //
Je voudrais me débarrasser de _OutputSize.
{
if(!_ToParse)
return NULL;
char *Str=malloc(_OutputSize+1); // Dans les exemples existants,
"_OutputSize" est souvent une constante.
if(!Str)
;
va_list ArgPtr;
va_start(ArgPtr, _ToParse);
vsprintf(Str, _ToParse, ArgPtr);
va_end(ArgPtr);
Str[_OutputSize]='';
return Str;
}



Il faut utiliser vsnprintf() pour eviter de deborder et augmenter la taille
allouée si nécessaire

Sinon question :
si je fais
void *NextArg=_ToParse;
NextArg=NextArg+1; // Là, je met bien la main sur le premier argument
facultatif suivant ?
NextArg=NextArg+1; // Et là, je passe bien au suivant ?
J'ai juste ?
Quelle que soit la plate-forme, ceci est toujours valable ?



Il faut utiliser va_arg() pour parcourir argument par argument, en precisant le
type.
SI je me souviens bien :

va_list ArgPtr ;
int par1 ;
char * par2 ;
va_start(ArgPtr, _ToParse) ;
par1 = *(va_arg(ArgPtr,int)) ;
par2 = *(va_arg(ArgPtr,char *)) ;

Avatar
Laurent Deniau
Al 1 wrote:
ça marchouille un peu avec un pécé pour plusieurs raisons, en
particulier parce que sizeof (int) == sizeof (void *), et parce que pour
un passage d'arguments variables, les char et short sont promus en
double.


Les char et les short sont promus en int. C'est aussi valable lorsque la
declaration de la fonction n'a pas d'arguments declares tel que void f();

a+, ld.

--
[ Laurent Deniau -- Scientific Computing & Data Analysis ]
[ CERN -- European Center for Nuclear Research ]
[ - http://cern.ch/Laurent.Deniau ]
[ -- One becomes old when dreams become regrets -- ]

Avatar
Laurent Deniau
Frédéri MIAILLE wrote:
Bonjour,
dans le formatage d'une chaîne de caractère en utilisant une fonction à
liste d'arguments variable, je me demande s'il est possible de trouver la
taille resultante de la chaine de caractère avant, bien évidemment, de la
formater...

inline char *Parse(unsigned int _OutputSize, const char *_ToParse, ...) //
Je voudrais me débarrasser de _OutputSize.
{
if(!_ToParse)
return NULL;
char *Str=malloc(_OutputSize+1); // Dans les exemples existants,
"_OutputSize" est souvent une constante.
if(!Str)
;
va_list ArgPtr;
va_start(ArgPtr, _ToParse);
vsprintf(Str, _ToParse, ArgPtr);
va_end(ArgPtr);
Str[_OutputSize]='';
return Str;
}

Sinon question :
si je fais
void *NextArg=_ToParse;
NextArg=NextArg+1; // Là, je met bien la main sur le premier argument
facultatif suivant ?
NextArg=NextArg+1; // Et là, je passe bien au suivant ?
J'ai juste ?
Quelle que soit la plate-forme, ceci est toujours valable ?

Merci de vos lumières.


Si tu es sous linux, le man de vsnprintf donne un exemple d'utilisation qui
repond a ta question. Si tu es en C90 (seulement vsprintf), je peux te fournir
du code qui resoud ton probleme.

a+, ld.

--
[ Laurent Deniau -- Scientific Computing & Data Analysis ]
[ CERN -- European Center for Nuclear Research ]
[ - http://cern.ch/Laurent.Deniau ]
[ -- One becomes old when dreams become regrets -- ]

Avatar
Al 1
Laurent Deniau a écrit:
Al 1 wrote:

les char et short sont promus en double.



Les char et les short sont promus en int.


oops, erreur de frappe


Avatar
Al 1
Frédéri MIAILLE a écrit:
Vraiment ?
Honnêtement, je ne comprend pas. Il faut bien un buffer capable de re çevoir
non seulement la taille de la chaine non formatée mais encore la tail le
supplémentaire que la conversion des symboles implique ?


J'ai donc mal compris ta question, j'ai répondu à:
"j'aimerais mettre une constante à la place de _OutputSize"

pour trouver sa valeur, une méthode (en C99) est :

_OutputSize = vsnprintf (NULL, 0, _ToParse, ArgPtr) + 1;

Avatar
Frédéri MIAILLE
pour trouver sa valeur, une méthode (en C99) est :
_OutputSize = vsnprintf (NULL, 0, _ToParse, ArgPtr) + 1;


Oh merci, t'es génial !


--
Frédéri MIAILLE
fr.comp.lang.c
fr.comp.lang.c++
fr.comp.os.ms-windows.programmation
fr.comp.graphisme.programmation

Avatar
Frédéri MIAILLE
Merci Yves et Laurent, c'est exactement ce qu'il me faut.


--
Frédéri MIAILLE
fr.comp.lang.c
fr.comp.lang.c++
fr.comp.os.ms-windows.programmation
fr.comp.graphisme.programmation
Avatar
Laurent Deniau
Frédéri MIAILLE wrote:
pour trouver sa valeur, une méthode (en C99) est :
_OutputSize = vsnprintf (NULL, 0, _ToParse, ArgPtr) + 1;


Oh merci, t'es génial !


Attention, bien tester que l'on est en C99 parce qu'il y a des vsnprintf pre-C99
qui n'ont pas ce joli comportement...

a+, ld.

--
[ Laurent Deniau -- Scientific Computing & Data Analysis ]
[ CERN -- European Center for Nuclear Research ]
[ - http://cern.ch/Laurent.Deniau ]
[ -- One becomes old when dreams become regrets -- ]


1 2