Como passar número variável de argumentos para printf / sprintf
-
20-08-2019 - |
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.
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.
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:
-
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)
-
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).