Je cherche à le faire en C / C ++.
Je suis tombé sur des arguments de longueur variable, mais cela suggère une solution avec Python & C utilisant libffi .
Maintenant, si je veux envelopper la fonction printf
avec myprintf
Ce que je fais est comme ci-dessous:
void myprintf(char* fmt, ...) { va_list args; va_start(args,fmt); printf(fmt,args); va_end(args); } int _tmain(int argc, _TCHAR* argv[]) { int a = 9; int b = 10; char v = 'C'; myprintf("This is a number: %d and \nthis is a character: %c and \n another number: %d\n",a, v, b); return 0; }
Mais les résultats ne sont pas comme prévu!
This is a number: 1244780 and this is a character: h and another number: 29953463
N’importe quel point où me manque-t-il?
le problème est que vous ne pouvez pas utiliser ‘printf’ avec va_args. Vous devez utiliser vprintf si vous utilisez des listes d’arguments variables. vprint, vsprintf, vfprintf, etc. (il existe également des versions «sûres» dans l’environnement d’exécution C de Microsoft qui empêchent les dépassements de mémoire tampon, etc.)
Vous échantillonnez fonctionne comme suit:
void myprintf(char* fmt, ...) { va_list args; va_start(args,fmt); vprintf(fmt,args); va_end(args); } int _tmain(int argc, _TCHAR* argv[]) { int a = 9; int b = 10; char v = 'C'; myprintf("This is a number: %d and \nthis is a character: %c and \n another number: %d\n",a, v, b); return 0; }
En C ++ 11, il s’agit d’une solution possible à l’aide des Variadic templates
:
template void myprintf(const char* fmt, Args... args ) { std::printf( fmt, args... ) ; }
MODIFIER
Comme @rubenvb le fait remarquer, il faut tenir compte de certains compromis. Par exemple, vous générerez du code pour chaque instance, ce qui mènera à un gonflement du code.
Je ne sais pas non plus ce que tu veux dire par pure
En C ++, nous utilisons
#include #include class Foo { void Write(const char* pMsg, ...); }; void Foo::Write( const char* pMsg, ...) { char buffer[4096]; std::va_list arg; va_start(arg, pMsg); std::vsnprintf(buffer, 4096, pMsg, arg); va_end(arg); ... }
En fait, il existe un moyen d’appeler une fonction qui n’a pas de version va_list
partir d’un wrapper. L’idée est d’utiliser l’assembleur, ne touchez pas les arguments de la stack et remplacez temporairement l’adresse de retour de la fonction.
Exemple pour Visual C x86. call addr_printf
appelle printf()
:
__declspec( thread ) static void* _tls_ret; static void __stdcall saveret(void *retaddr) { _tls_ret = retaddr; } static void* __stdcall _getret() { return _tls_ret; } __declspec(naked) static void __stdcall restret_and_return_int(int retval) { __asm { call _getret mov [esp], eax ; /* replace current retaddr with saved */ mov eax, [esp+4] ; /* retval */ ret 4 } } static void __stdcall _dbg_printf_beg(const char *fmt, va_list args) { printf("calling printf(\"%s\")\n", fmt); } static void __stdcall _dbg_printf_end(int ret) { printf("printf() returned %d\n", ret); } __declspec(naked) int dbg_printf(const char *fmt, ...) { static const void *addr_printf = printf; /* prolog */ __asm { push ebp mov ebp, esp sub esp, __LOCAL_SIZE nop } { va_list args; va_start(args, fmt); _dbg_printf_beg(fmt, args); va_end(args); } /* epilog */ __asm { mov esp, ebp pop ebp } __asm { call saveret call addr_printf push eax push eax call _dbg_printf_end call restret_and_return_int } }
Utilisez-vous C ou C ++? La prochaine version de C ++, C ++ 0x, prendra en charge les modèles variadiques qui apportent une solution à ce problème.
Une autre solution peut être obtenue en surchargeant les opérateurs pour obtenir une syntaxe comme celle-ci:
void f(varargs va) { BOOST_FOREACH(varargs::iterator i, va) cout << *i << " "; } f(args = 1, 2, 3, "Hello");
Pour que cela fonctionne, la classe varargs
doit être implémentée pour remplacer operator =
qui renvoie un object proxy qui, à son tour, remplace l' operator ,
. Cependant, rendre ce type de variante sûr dans le C ++ actuel n'est pas possible pour autant que je sache, car il devrait fonctionner par type d'effacement.
Comment voulez-vous une solution C / C ++ pure?
Le paramètre rest (…) est pris en charge multi-plateforme dans le runtime C.
void myprintf(char* fmt, ...) { va_ list args; va_ start(args,fmt); printf(fmt,args); ----> This is the fault. vprintf(fmt, args); should have been used. va_ end(args); } If you're just trying to call printf, there's a printf variant called vprintf that takes the va_list directly : vprintf(fmt, args);