Frage

Ich möchte dies in C/C++ tun.

Ich bin rübergekommen Argumente mit variabler Länge Dies legt jedoch eine Lösung mit Python und C nahe libffi.

Nun, wenn ich einpacken möchte printf Funktion mit myprintf

Was ich mache, ist wie folgt:

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

Aber die Ergebnisse sind nicht wie erwartet!

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

Irgendein Punkt, wo habe ich übersehen??

War es hilfreich?

Lösung

Das Problem ist, dass Sie „printf“ nicht mit va_args verwenden können.Du musst benutzen vprintf wenn Sie variable Argumentlisten verwenden.vprint, vsprintf, vfprintf usw.(Es gibt auch „sichere“ Versionen in der C-Laufzeitumgebung von Microsoft, die Pufferüberläufe usw. verhindern.)

Ihre Beispielarbeiten lauten wie folgt:

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

Andere Tipps

In C++11 ist dies eine mögliche Lösung mit Variadic templates:

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

BEARBEITEN

Wie @rubenvb hervorhebt, sind Kompromisse zu berücksichtigen. Beispielsweise generieren Sie Code für jede Instanz, was zu einer Aufblähung des Codes führt.

Ich bin mir auch nicht sicher, was du mit rein meinst

In C++ verwenden wir

#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);
    ...
}

Tatsächlich gibt es eine Möglichkeit, eine Funktion aufzurufen, die nein hat va_list Version aus einem Wrapper.Die Idee besteht darin, Assembler zu verwenden, Argumente im Stapel nicht zu berühren und die Rückgabeadresse der Funktion vorübergehend zu ersetzen.

Beispiel für Visual C x86. call addr_printf Anrufe 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
    }
}

Verwenden Sie C oder C++?Die nächste C++-Version, C++0x, wird unterstützen Verschiedene Vorlagen die eine Lösung für dieses Problem bieten.

Eine weitere Problemumgehung kann durch geschicktes Überladen von Operatoren erreicht werden, um eine Syntax wie diese zu erreichen:

void f(varargs va) {
    BOOST_FOREACH(varargs::iterator i, va)
        cout << *i << " ";
}

f(args = 1, 2, 3, "Hello");

Damit dies funktioniert, muss die Klasse varargs muss zum Überschreiben implementiert werden operator = das gibt ein Proxy-Objekt zurück, das wiederum überschreibt operator ,.Allerdings ist es meines Wissens nicht möglich, diesen Variantentyp im aktuellen C++ sicher zu machen, da dies durch Typlöschung funktionieren müsste.

Wie meinen Sie eine reine C/C++-Lösung?

Der Rest-Parameter (...) wird in der C-Laufzeit plattformübergreifend unterstützt.

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);
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top