web-dev-qa-db-de.com

So übergeben Sie eine variable Anzahl von Argumenten an printf / sprintf

Ich habe eine Klasse, die eine "Fehler" -Funktion enthält, die Text formatiert. Ich möchte eine variable Anzahl von Argumenten akzeptieren und sie dann mit printf formatieren.

Beispiel:

class MyClass
{
public:
    void Error(const char* format, ...);
};

Die Error-Methode sollte die Parameter aufnehmen, printf/sprintf aufrufen, um sie zu formatieren und dann etwas damit zu tun. Ich möchte nicht die gesamte Formatierung selbst schreiben, daher ist es sinnvoll, herauszufinden, wie die vorhandene Formatierung verwendet wird.

75
user5722
void Error(const char* format, ...)
{
    va_list argptr;
    va_start(argptr, format);
    vfprintf(stderr, format, argptr);
    va_end(argptr);
}

Wenn Sie die Zeichenfolge manipulieren möchten, bevor Sie sie anzeigen und sie wirklich zuerst in einem Puffer speichern müssen, verwenden Sie vsnprintf anstelle von vsprintf. vsnprintf verhindert einen versehentlichen Pufferüberlauffehler.

141
John Kugelman

schauen Sie sich vsnprintf an, da dies tun wird, was Sie wollen http://www.cplusplus.com/reference/clibrary/cstdio/vsprintf/

sie müssen zuerst das Array va_list arg initialisieren und es dann aufrufen.

Beispiel von diesem Link:/* vsprintf example * /

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

Die Verwendung von Funktionen mit den Ellipsen ist nicht sehr sicher. Wenn die Leistung für die Protokollfunktion nicht kritisch ist, sollten Sie die Operatorüberladung wie im boost :: -Format verwenden. Sie könnten so etwas schreiben:

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

Das folgende Beispiel zeigt mögliche Fehler mit Ellipsen:

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.

Ich hätte mehr über bestehende Fragen im Stapelüberlauf lesen sollen.

C++ Übergabe variabler Anzahl von Argumenten ist eine ähnliche Frage. Mike F hat die folgende Erklärung:

Es gibt keine Möglichkeit, printf aufzurufen, ohne zu wissen, wie viele Argumente Sie an printf übergeben, es sei denn, Sie möchten sich auf freche und nicht tragbare Tricks einlassen.

Die allgemein verwendete Lösung besteht darin, immer eine alternative Form von vararg-Funktionen bereitzustellen. Printf hat also vprintf, das eine va_list anstelle der ... -Versionen verwendet. Die ... -Versionen sind nur Wrapper um die va_list-Versionen.

Genau das habe ich gesucht. Ich habe eine Testimplementierung wie folgt durchgeführt:

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);
}
3
user5722

Sie suchen verschiedene Funktionen . printf () und sprintf () sind variable Funktionen - sie können eine variable Anzahl von Argumenten akzeptieren.

Dies beinhaltet im Wesentlichen die folgenden Schritte:

  1. Der erste Parameter muss einen Hinweis auf die Anzahl der folgenden Parameter geben. In printf () gibt der Parameter "format" diese Angabe an. Wenn Sie 5 Formatspezifizierer haben, sucht er nach 5 weiteren Argumenten (für insgesamt 6 Argumente). Das erste Argument kann eine Ganzzahl sein (z. B. "myfunction") (3, a, b, c) "wobei" 3 "" 3 Argumente "bedeutet)

  2. Durchlaufen Sie dann jedes nachfolgende Argument und rufen Sie es mit den Funktionen va_start () usw. ab.

Es gibt viele Tutorials dazu - viel Glück!

3
poundifdef

Einfaches Beispiel unten. Beachten Sie, dass Sie einen größeren Puffer übergeben und testen sollten, ob der Puffer groß genug ist oder nicht

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
}
2
DougN

Schauen Sie sich das Beispiel an http://www.cplusplus.com/reference/clibrary/cstdarg/va_arg/ , sie übergeben die Anzahl der Argumente an die Methode, aber Sie können das weglassen und den Code ändern passend (siehe Beispiel).

0
stefanB