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

6 réponses

1 2
Avatar
Frédéri MIAILLE
"Laurent Deniau" a écrit dans le message de
news:
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...
Désolé pour le HS mais :

_OutputSize = vsnprintf (NULL, 0, _ToParse, ArgPtr) + 1;
n'existe pas sous ma plate-forme.
Et à la place je tente d'utiliser
_OutputSize = _vsnprintf (NULL, 0, _ToParse, ArgPtr) + 1;
qui me plante avec l'assert !=NULL sur le premier paramètre.
Avec une chaine allouée de 1 caractère, il me renvoie -1.
Comment faire ? ([HS]Je suis sous Windows[/HS]).

--
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:
"Laurent Deniau" a écrit dans le message de
news:

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...


Désolé pour le HS mais :
_OutputSize = vsnprintf (NULL, 0, _ToParse, ArgPtr) + 1;
n'existe pas sous ma plate-forme.
Et à la place je tente d'utiliser
_OutputSize = _vsnprintf (NULL, 0, _ToParse, ArgPtr) + 1;
qui me plante avec l'assert !=NULL sur le premier paramètre.
Avec une chaine allouée de 1 caractère, il me renvoie -1.
Comment faire ? ([HS]Je suis sous Windows[/HS]).


C'est justement ce que je voulais souligner, certains vsnprintf pre-C99
renvoient -1 en cas de taille buffer insuffisante.

Il faut proceder par iteration en doublant la taille du buffer tant que
vsnprintf renvoie -1 et eventuellement reajuster la taille a la fin.

Sinon utilise vfprintf (C90) sur le 'null device' de ton OS (/dev/null sous
Unix) ou sur un fichier temporaire (cf tmpfile, c'est C90) pour obtenir la
taille du buffer.

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
Frédéri MIAILLE
Ok bon merci.
Je définis une constante pour la taille de la chaine et puis voilà.
Je contrôle s'il y à erreur au niveau de la taille (si _vsnprintf
renvoie -1) auquel cas l'utilisateur changera la taille du buffer.
C'est plus simple et certainement plus rapide que boucler sur le _vsnprintf
jusqu'à ce qu'il renvoie une taille valide.

Merci beaucoup 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
Al 1
Frédéri MIAILLE a écrit:
Ok bon merci.
Je définis une constante pour la taille de la chaine et puis voilà.
Je contrôle s'il y à erreur au niveau de la taille (si _vsnprintf
renvoie -1) auquel cas l'utilisateur changera la taille du buffer.
C'est plus simple et certainement plus rapide que boucler sur le _vsnpr intf
jusqu'à ce qu'il renvoie une taille valide.

Merci beaucoup en tout cas.



béh non c'est simple

char *tmp;
int res;
_OutputSize = 2;
_ToParse = NULL;
do {
tmp = realloc (Str, _OutputSize);
if (tmp == NULL) {free (Str); return NULL;}
Str = tmp;

res = vsnprintf (Str, _ToParse, ArgPtr);

/* Cas du renvoi de -1 si c'est trop grand */
if (res == -1) _OutputSize *= 2;

/* Cas C99-compliant */
if (res >= _OutputSize) _OutputSize = res + 1;

} while (res >= 0 && res < _OutputSize);

Avatar
Al 1
Frédéri MIAILLE a écrit:
Ok bon merci.
Je définis une constante pour la taille de la chaine et puis voilà .
Je contrôle s'il y à erreur au niveau de la taille (si _vsnprintf
renvoie -1) auquel cas l'utilisateur changera la taille du buffer.
C'est plus simple et certainement plus rapide que boucler sur le
_vsnprintf

jusqu'à ce qu'il renvoie une taille valide.

Merci beaucoup en tout cas.



béh non c'est simple

char *tmp;
int res;
_OutputSize = 2;
_ToParse = NULL;
do {
tmp = realloc (Str, _OutputSize);
if (tmp == NULL) {free (Str); return NULL;}
Str = tmp;

res = vsnprintf (Str, _ToParse, ArgPtr);

/* Cas du renvoi de -1 si c'est trop grand */
if (res == -1) _OutputSize *= 2;

/* Cas C99-compliant */
if (res >= _OutputSize) _OutputSize = res + 1;

} while (res == -1 || res >= _OutputSize);

Avatar
Frédéri MIAILLE
béh non c'est simple

char *tmp;
int res;
_OutputSize = 2;
_ToParse = NULL;
do {
tmp = realloc (Str, _OutputSize);
if (tmp == NULL) {free (Str); return NULL;}
Str = tmp;

res = vsnprintf (Str, _ToParse, ArgPtr);

/* Cas du renvoi de -1 si c'est trop grand */
if (res == -1) _OutputSize *= 2;

/* Cas C99-compliant */
if (res >= _OutputSize) _OutputSize = res + 1;

} while (res == -1 || res >= _OutputSize);


Merci infiniment mais
"while (res == -1 || res >= _OutputSize);" me gêne pour une simple copie.
C'est long pour moi surtout que ma chaîne peut gonfler de 1 octet à 1
méga-octet.
Aussi :
"_OutputSize *= 2;"
me gêne un peu (bien que fonctionnel) car pour 1 octet manquant je peux
avoir 999Ko de supplément non utilisés.
Je préfère emmerder le programmeur mais je préfère privilégier les
microsecondes.
Pour la petite histoire, j'ai besoin de faire appel à cette fonction dans la
boucle principale et elle sera appelée en permanence.
D'ou le "HIC".
Dans le cas d'un code normé C90 (on dit comme ça ? je me trompe ?), ça
aurait été super (mais je le garde pour ma version Linux donc le fil de
discussion m'a été fort utile).
Oui, la programmation, c'est comme les femmes, quand on a un problème au
niveau de la norme on est obligé de s'emmerder avec des détails.

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

1 2