Pergunta

Eu tenho uma classe que detém uma função de "erro" que irá formatar algum texto. Eu quero aceitar um número variável de argumentos e, em seguida, formatá-los usando printf.

Exemplo:

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

O método de erro deve tomar na parâmetros, printf chamada / sprintf para formatá-lo e, em seguida, fazer algo com ele. Eu não quero escrever toda a formatação de mim mesmo por isso faz sentido para tentar descobrir como usar a formatação existente.

Foi útil?

Solução

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

Se você deseja manipular a corda antes de exibi-lo e realmente precisa dele armazenadas em um buffer primeiro, uso vsnprintf em vez de vsprintf. vsnprintf irá impedir que um erro acidental tampão de transbordamento.

Outras dicas

ter um olhar para vsnprintf como isso vai fazer o que ya quer http: // www .cplusplus.com / reference / clibrary / cstdio / vsprintf /

você terá que inicializar o conjunto va_list arg em primeiro lugar, em seguida, chamá-lo.

Exemplo a partir desse link: / * Exemplo vsprintf * /

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

Usando funções com as elipses não é muito seguro. Se o desempenho não é crítico para a função log considerar o uso de sobrecarga de operador como em boost :: formato. Você poderia escrever algo como isto:

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

O exemplo a seguir demonstra possíveis erros com elipses:

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.

Eu deveria ter ler mais sobre as questões existentes no estouro de pilha.

??C ++ Passando variável número de argumentos é uma pergunta semelhante. Mike F tem a seguinte explicação:

Não há nenhuma maneira de chamar (por exemplo) printf sem saber como muitos argumentos você está passando a ela, a menos que você quiser para entrar impertinente e não-portáteis truques.

A solução geralmente é utilizado para sempre fornecer uma forma alternativa de funções vararg, então printf tem vprintf que leva um va_list no lugar do .... Os ... versões são apenas wrappers para as versões va_list.

Este é exatamente o que eu estava procurando. Eu realizada uma implementação de teste como este:

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

Você está procurando funções variádicos . printf () e sprintf () são funções variádicos - eles podem aceitar um número variável de argumentos

.

Isto implica basicamente essas etapas:

  1. O primeiro parâmetro deve dar alguma indicação sobre o número de parâmetros que se seguem. Assim, em printf (), o parâmetro "format" dá esta indicação - (. Para um total de 6 argumentos) se você tem 5 especificadores de formato, em seguida, ele irá procurar por mais 5 argumentos O primeiro argumento poderia ser um inteiro (por exemplo, "myfunction (3, a, b, c) "onde "3" significa" 3 argumentos)

  2. lacete seguida através e recuperar cada argumento sucessivas, utilizando o va_start () etc funções.

Há uma abundância de tutoriais sobre como fazer isso - boa sorte

Um exemplo simples abaixo. Observe que você deve passar em um buffer maior, e teste para ver se o buffer é grande o suficiente ou não

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
}

Tenha um olhar para o exemplo http://www.cplusplus.com/ referência / clibrary / cstdarg / va_arg / , eles passam o número de argumentos para o método, mas você pode omitir isso e modificar o código apropriadamente (veja o exemplo).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top