parameter c++ c variadic-functions

parameter - c++ variadic templates



¿Cómo envolver una función con argumentos de longitud variable? (7)

Estoy buscando hacer esto en C / C ++.

Encontré Argumentos de longitud variable pero esto sugiere una solución con Python & C usando libffi .

Ahora, si quiero ajustar la función printf con myprintf

Lo que hago es como a continuación:

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; }

¡Pero los resultados no son los esperados!

This is a number: 1244780 and this is a character: h and another number: 29953463

¿En algún punto donde extrañé?


¿Estás usando C o C ++? La próxima versión de C ++, C ++ 0x, admitirá plantillas variadas que proporcionan una solución a ese problema.

Se puede lograr otra solución mediante la sobrecarga inteligente del operador para lograr una sintaxis como esta:

void f(varargs va) { BOOST_FOREACH(varargs::iterator i, va) cout << *i << " "; } f(args = 1, 2, 3, "Hello");

Para que esto funcione, la clase varargs debe implementarse para anular operator = que devuelve un objeto proxy que, a su vez, anula operator , . Sin embargo, por lo que sé, hacer que este tipo de variante sea seguro en C ++ actual no es posible, ya que tendría que funcionar por tipo de borrado.



el problema es que no puedes usar ''printf'' con va_args. Debe usar vprintf si está utilizando listas de argumentos variables. vprint, vsprintf, vfprintf, etc. (también hay versiones "seguras" en el tiempo de ejecución de C de Microsoft que evitarán los excesos de memoria, etc.)

Tu muestra funciona de la siguiente manera:

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, esta es una solución posible que utiliza Variadic templates :

template<typename... Args> void myprintf(const char* fmt, Args... args ) { std::printf( fmt, args... ) ; }

EDITAR

Como @rubenvb señala que hay consideraciones que considerar, por ejemplo, generará código para cada instancia que conducirá a la saturación del código.


También estoy seguro de lo que quieres decir con puro

En C ++ usamos

#include <cstdarg> #include <cstdio> 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 realidad, hay una manera de llamar a una función que no tiene una versión de va_list desde un contenedor. La idea es usar ensamblador, no tocar argumentos en la pila, y reemplazar temporalmente la dirección de retorno de la función.

Ejemplo para Visual C x86. call addr_printf llamadas 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 } }


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);