Question

Je cherche à faire cela en C/C++.

Je suis tombé sur Arguments de longueur variable mais cela suggère une solution avec Python & C en utilisant libffi.

Maintenant, si je veux conclure printf fonctionner 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 ceux espérés !

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

Un moment où ai-je raté ??

Était-ce utile?

La solution

le problème est que vous ne pouvez pas utiliser 'printf' avec va_args.Tu dois utiliser vprintf si vous utilisez des listes d'arguments variables.vprint, vsprintf, vfprintf, etc.(il existe également des versions « sûres » dans le runtime C de Microsoft qui empêcheront les dépassements de tampon, etc.)

Vous échantillonnez les travaux 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;
}

Autres conseils

En C++11, c'est une solution possible en utilisant Variadic templates:

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

MODIFIER

Comme @rubenvb le souligne, il y a des compromis à considérer, par exemple, vous générerez du code pour chaque instance, ce qui entraînera une surcharge du code.

Je ne suis pas sûr non plus de ce que tu entends par pur

En C++, nous utilisons

#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 fait, il existe un moyen d'appeler une fonction qui n'a pas va_list version à partir d'un wrapper.L'idée est d'utiliser l'assembleur, de ne pas toucher aux arguments dans la pile et de remplacer temporairement l'adresse de retour de la fonction.

Exemple pour Visual C x86. call addr_printf appels 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 C++, C++0x, prendra en charge modèles variadiques qui apportent une solution à ce problème.

Une autre solution de contournement peut être obtenue par une surcharge intelligente des 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 mis en œuvre pour remplacer operator = qui renvoie un objet proxy qui, à son tour, remplace operator ,.Cependant, à ma connaissance, rendre ce type de variante sûr dans le C++ actuel n'est pas possible car il devrait fonctionner par effacement de type.

Comment entendez-vous une solution pure C/C++ ?

Le paramètre rest (...) est pris en charge sur plusieurs plates-formes dans le runtime C.

http://msdn.microsoft.com/en-us/library/kb57fad8.aspx

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);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top