Как передать переменное количество аргументов в printf / sprintf
У меня есть класс, который содержит функцию "ошибки", которые форматируют текст. Я хочу принять переменное количество аргументов, а затем отформатировать их с помощью printf.
пример:
class MyClass
{
public:
void Error(const char* format, ...);
};
метод ошибки должен принимать параметры, вызывать printf / sprintf для его форматирования, а затем что-то с ним делать. Я не хочу писать все форматирование сам, поэтому имеет смысл попробовать и выяснить, как использовать существующее форматирование.
7 ответов:
плохо
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); }
этот код не так хорошо. Он использует буфер символов фиксированного размера, который может привести к ошибке переполнения буфера, если строка патологически длинная. Произвольный большой
1024*16
размер должен установить флаг в твоей голове. Кроме того,printf
звонок может столкнуться с проблемами, еслиdest
в конечном итоге содержит коды форматирования. Лучше бы былоprintf("%s", dest)
. Но еще лучше было бы использоватьvprintf
илиvfprintf
:хороший
void Error(const char* format, ...) { va_list argptr; va_start(argptr, format); vfprintf(stderr, format, argptr); va_end(argptr); }
если вы хотите манипулировать строкой перед ее отображением и действительно хотите, чтобы она сначала хранилась в буфере, пожалуйста, используйте
vsnprintf
вместоvsprintf
.vsnprintf
предотвратит случайную ошибку переполнения буфера.
посмотрите на vsnprintf, как это будет делать то, что вы хотитеhttp://www.cplusplus.com/reference/clibrary/cstdio/vsprintf/
сначала вам нужно будет инициализировать массив arg va_list, а затем вызвать его.
пример из этой ссылке: /* пример 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); }
использование функций с эллипсами не очень безопасно. Если производительность не критична для функции журнала, рассмотрите возможность использования перегрузки оператора, как в формате boost::. Вы могли бы написать что-то вроде этого:
#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; }
в следующем примере показаны возможные ошибки с многоточиями:
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.
Я должен был прочитать больше о существующих вопросах в Stack overflow.
C++ передача переменного числа аргументов на подобный вопрос. Майк F имеет следующее объяснение:
нет никакого способа вызова (например) printf не зная, сколько аргументов вы переходите к нему, если вы хотите чтобы попасть в непослушный и не портативный трюки.
обычно используемое решение состоит в том, чтобы всегда предлагаем альтернативную форму функции с переменным числом аргументов, так е есть vprintf, который занимает va_list на месте из.... Этот... версии есть только обертки вокруг версий va_list.
Это именно то, что я искал. Я выполнил тестовую реализацию следующим образом:
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); }
вы ищете variadic функции. printf () и sprintf () являются вариативными функциями - они могут принимать переменное число аргументов.
Это влечет за собой в основном следующие шаги:
первый параметр должен дать некоторое представление о количестве параметров, которые следуют. Поэтому в printf () параметр "format" дает это указание - если у вас есть 5 спецификаторов формата, то он будет искать еще 5 аргументов (всего 6 аргументы.) Первый аргумент может быть целым числом (например, " myfunction(3, a, b, c)", где "3" означает "3 аргумента)
затем выполните цикл и извлеките каждый последующий аргумент, используя va_start () и т. д. функции.
есть много учебников о том, как это сделать - удачи!
простой пример ниже. Обратите внимание, что вы должны пройти в более крупный буфер и проверить, был ли буфер достаточно большим или нет
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 }
взгляните на Пример http://www.cplusplus.com/reference/clibrary/cstdarg/va_arg/, они передают количество аргументов в метод, но вы можете оммить это и соответствующим образом изменить код (см. Пример).