가변 개수의 인수를 printf / sprintf에 전달하는 방법


83

일부 텍스트를 형식화하는 "오류"함수를 보유하는 클래스가 있습니다. 가변 개수의 인수를 수락 한 다음 printf를 사용하여 형식을 지정하고 싶습니다.

예:

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

Error 메서드는 매개 변수를 가져 와서 printf / sprintf를 호출하여 형식을 지정한 다음 작업을 수행해야합니다. 모든 서식을 직접 작성하고 싶지 않으므로 기존 서식을 사용하는 방법을 시도하고 파악하는 것이 합리적입니다.

답변:


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

당신은 당신이 사용을 표시하고 정말 처음 버퍼에 저장 필요성을하기 전에 문자열을 조작하려면 vsnprintf대신을 vsprintf. vsnprintf우발적 인 버퍼 오버 플로우 오류를 방지합니다.


37

이것은 당신이 원하는 것을 할 것이므로 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);
}

6
vsnprintf 의 두 번째 인수는 종료 널 바이트 ( '\ 0')를 포함하여 버퍼 길이 여야합니다. 당신은 255 대신 함수 호출에 256을 사용할 수 있도록
aviggiano

마법의 숫자를 통과하는 것은 나쁜이 ... 사용하는 것입니다 sizeof(buffer)대신 256의
Anonymouse

4

스택 오버플로의 기존 질문에 대해 더 많이 읽어야했습니다.

C ++ Passing Variable Number of Arguments 는 비슷한 질문입니다. Mike F의 설명은 다음과 같습니다.

당신이 장난스럽고 이식 불가능한 속임수를 쓰길 원하지 않는 한, 당신이 얼마나 많은 인수를 전달하고 있는지 알지 않고는 printf를 호출 할 방법이 없습니다.

일반적으로 사용되는 솔루션은 항상 대체 형태의 vararg 함수를 제공하는 것이므로 printf에는 ... 대신 va_list를 사용하는 vprintf가 있습니다. ... 버전은 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);
}

마지막 'printf (dest);' 형식이 잘못되었습니다. 최소한 형식 문자열도 필요합니다.
Jonathan Leffler

문자열이 형식 문자열이기 때문에 그렇지 않습니다. 즉, printf ( "a string"); 괜찮
Lodle

4
dest에 "% s"또는 "% d"가 포함될 때까지 printf (dest)를 사용하고 BOOM을 사용할 수 있습니다. printf ( "% s", dest)를 사용하십시오.
John Kugelman 2009-06-29

코어 덤프가 최상의 시나리오라는 점을 지적하고 싶을뿐입니다. 서버 코드에서 그렇게하면 해커가 아침 식사로 CPU를 사용할 것입니다.
MickLH

"% .16383s"를 사용하면 어레이 대상이 오버플로되지 않도록 보호됩니다. ( '\ 0'터미네이터 허용)
eddyq

3

가변 함수를 찾고 있습니다 . printf () 및 sprintf ()는 가변 함수입니다. 가변 개수의 인수를받을 수 있습니다.

이것은 기본적으로 다음 단계를 수반합니다.

  1. 첫 번째 매개 변수는 뒤에 오는 매개 변수의 수를 표시해야합니다. 따라서 printf ()에서 "format"매개 변수는이 표시를 제공합니다. 5 개의 형식 지정자가 있으면 5 개의 추가 인수 (총 6 개의 인수)를 찾습니다. 첫 번째 인수는 정수가 될 수 있습니다 (예 : "myfunction (3, a, b, c) "여기서"3 "은"3 개의 인수를 의미합니다.)

  2. 그런 다음 va_start () 등의 함수를 사용하여 각 연속 인수를 반복하고 검색합니다.

이를 수행하는 방법에 대한 많은 자습서가 있습니다-행운을 빕니다!


3

생략 부호가있는 함수를 사용하는 것은 그리 안전하지 않습니다. 로그 기능에 성능이 중요하지 않은 경우 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.

5
이것은 쉬운 일을 어렵게 만드는 방법입니다.
eddyq

2
"타원이있는 함수를 사용하는 것은 그리 안전하지 않습니다." 유일한 안전한 대안이 C ++ 및 부스트와 관련된 경우 "별로 안전하지 않음"이 의미하는 바를 설명하고 올바른 형식 지정자를 사용하면 printf 함수가 완벽하게 안전하다는 점을 언급해야합니다.
osvein

2

아래의 간단한 예. 더 큰 버퍼를 전달하고 버퍼가 충분히 큰지 테스트해야합니다.

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
}

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.