J'ai une classe qui contient une fonction "erreur" qui formatera du texte. Je veux accepter un nombre variable d'arguments, puis les formater à l'aide de printf.
Exemple:
class MyClass
{
public:
void Error(const char* format, ...);
};
La méthode Error doit prendre en compte les paramètres, appelez printf/sprintf pour le formater puis faites quelque chose avec. Je ne veux pas écrire tout le formatage moi-même, il est donc logique d'essayer de comprendre comment utiliser le formatage existant.
void Error(const char* format, ...)
{
va_list argptr;
va_start(argptr, format);
vfprintf(stderr, format, argptr);
va_end(argptr);
}
Si vous voulez manipuler la chaîne avant de l'afficher et que vous en avez réellement besoin, elle sera d'abord stockée dans un tampon, utilisez vsnprintf
au lieu de vsprintf
. vsnprintf
empêchera une erreur de débordement de tampon accidentelle.
jetez un oeil à vsnprintf car cela fera ce que vous voulez http://www.cplusplus.com/reference/clibrary/cstdio/vsprintf/
vous devrez d'abord initialiser le tableau arg va_list, puis appelez-le.
Exemple à partir de ce lien:/* exemple vsprintf * /
#include <stdio.h>
#include <stdarg.h>
void Error (char * format, ...)
{
char buffer[256];
va_list args;
va_start (args, format);
vsnprintf (buffer, 255, format, args);
//do something with the error
va_end (args);
}
L'utilisation de fonctions avec les ellipses n'est pas très sûre. Si les performances ne sont pas critiques pour la fonction de journalisation, envisagez d'utiliser la surcharge de l'opérateur comme dans boost :: format. Vous pourriez écrire quelque chose comme ceci:
#include <sstream>
#include <boost/format.hpp>
#include <iostream>
using namespace std;
class formatted_log_t {
public:
formatted_log_t(const char* msg ) : fmt(msg) {}
~formatted_log_t() { cout << fmt << endl; }
template <typename T>
formatted_log_t& operator %(T value) {
fmt % value;
return *this;
}
protected:
boost::format fmt;
};
formatted_log_t log(const char* msg) { return formatted_log_t( msg ); }
// use
int main ()
{
log("hello %s in %d-th time") % "world" % 10000000;
return 0;
}
L'exemple suivant illustre les erreurs possibles avec les ellipses:
int x = SOME_VALUE;
double y = SOME_MORE_VALUE;
printf( "some var = %f, other one %f", y, x ); // no errors at compile time, but error at runtime. compiler do not know types you wanted
log( "some var = %f, other one %f" ) % y % x; // no errors. %f only for compatibility. you could write %1% instead.
J'aurais dû en savoir plus sur les questions existantes concernant le débordement de pile.
Nombre variable d'arguments C++ est une question similaire. Mike F a l'explication suivante:
Il n'y a aucun moyen d'appeler (par exemple) printf sans connaître le nombre d'arguments que vous lui transmettez, à moins que vous ne vouliez vous lancer dans des trucs coquins et non portables.
La solution généralement utilisée est de toujours fournir une forme alternative de fonctions vararg. Par conséquent, printf a vprintf qui remplace par va_list .... Les versions ... ne sont que des wrappers autour des versions de va_list.
Ceci est exactement ce que je cherchais. J'ai effectué une implémentation de test comme ceci:
void Error(const char* format, ...)
{
char dest[1024 * 16];
va_list argptr;
va_start(argptr, format);
vsprintf(dest, format, argptr);
va_end(argptr);
printf(dest);
}
Vous recherchez fonctions variadiques . printf () et sprintf () sont des fonctions variadiques - elles peuvent accepter un nombre variable d'arguments.
Cela implique essentiellement ces étapes:
Le premier paramètre doit donner une indication du nombre de paramètres qui suivent. Ainsi, dans printf (), le paramètre "format" donne cette indication - si vous avez 5 spécificateurs de format, il recherchera alors 5 arguments supplémentaires (pour un total de 6 arguments). Le premier argument pourrait être un entier (par exemple, "myfunction (3, a, b, c) "où" 3 "signifie" 3 arguments "
Ensuite, parcourez et récupérez chaque argument successif, en utilisant les fonctions va_start (), etc.
Il y a beaucoup de tutoriels sur la façon de le faire - bonne chance!
Exemple simple ci-dessous. Notez que vous devriez passer dans un tampon plus grand et tester pour voir si le tampon était assez grand ou pas.
void Log(LPCWSTR pFormat, ...)
{
va_list pArg;
va_start(pArg, pFormat);
char buf[1000];
int len = _vsntprintf(buf, 1000, pFormat, pArg);
va_end(pArg);
//do something with buf
}
Regardez l'exemple http://www.cplusplus.com/reference/clibrary/cstdarg/va_arg/ , ils transmettent le nombre d'arguments à la méthode, mais vous pouvez l'omettre et modifier le code. de manière appropriée (voir l'exemple).