가변 개수의 인수를 printf / sprintf에 전달하는 방법
일부 텍스트를 형식화하는 "오류"함수를 보유하는 클래스가 있습니다. 가변 개수의 인수를 수락 한 다음 printf를 사용하여 형식을 지정하고 싶습니다.
예:
class MyClass
{
public:
void Error(const char* format, ...);
};
Error 메서드는 매개 변수를 가져 와서 printf / sprintf를 호출하여 형식을 지정한 다음 작업을 수행해야합니다. 모든 서식을 직접 작성하고 싶지 않으므로 기존 서식을 사용하는 방법을 시도하고 파악하는 것이 합리적입니다.
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/
먼저 va_list arg 배열을 초기화 한 다음 호출해야합니다.
해당 링크의 예 : / * 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 :: format에서와 같이 연산자 오버로딩을 사용하는 것이 좋습니다. 다음과 같이 작성할 수 있습니다.
#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.
스택 오버플로의 기존 질문에 대해 더 많이 읽어야했습니다.
C ++ Passing Variable Number of Arguments 는 비슷한 질문입니다. Mike F의 설명은 다음과 같습니다.
당신이 장난스럽고 이식 불가능한 속임수를 쓰길 원하지 않는 한, 당신이 얼마나 많은 인수를 전달하고 있는지 알지 않고는 printf를 호출 할 방법이 없습니다.
The generally used solution is to always provide an alternate form of vararg functions, so printf has vprintf which takes a va_list in place of the .... The ... versions are just wrappers around the va_list versions.
This is exactly what I was looking for. I performed a test implementation like this:
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);
}
You are looking for variadic functions. printf() and sprintf() are variadic functions - they can accept a variable number of arguments.
This entails basically these steps:
The first parameter must give some indication of the number of parameters that follow. So in printf(), the "format" parameter gives this indication - if you have 5 format specifiers, then it will look for 5 more arguments (for a total of 6 arguments.) The first argument could be an integer (eg "myfunction(3, a, b, c)" where "3" signifies "3 arguments)
Then loop through and retrieve each successive argument, using the va_start() etc. functions.
There are plenty of tutorials on how to do this - good luck!
Simple example below. Note you should pass in a larger buffer, and test to see if the buffer was large enough or not
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
}
Have a look at the example http://www.cplusplus.com/reference/clibrary/cstdarg/va_arg/, they pass the number of arguments to the method but you can ommit that and modify the code appropriately (see the example).
'Programing' 카테고리의 다른 글
C #에서 알 수없는 길이의 배열 (0) | 2020.10.16 |
---|---|
NULL이 선언되지 않은 이유는 무엇입니까? (0) | 2020.10.16 |
MySQL에서 주별로 그룹화하는 방법은 무엇입니까? (0) | 2020.10.16 |
작업 중 하나에 대한 레이아웃 끄기 (0) | 2020.10.16 |
UIBarButtonItem : 대상 작업이 작동하지 않습니까? (0) | 2020.10.16 |