문제

C/C++에서 이 작업을 수행하려고 합니다.

나는 우연히 만났다 가변 길이 인수 하지만 이것은 다음을 사용하여 Python & C를 사용한 솔루션을 제안합니다. libffi.

이제 포장하고 싶다면 printf 기능 myprintf

내가 하는 일은 아래와 같습니다.

void myprintf(char* fmt, ...)
{
    va_list args;
    va_start(args,fmt);
    printf(fmt,args);
    va_end(args);
}

int _tmain(int argc, _TCHAR* argv[])
{
    int a = 9;
    int b = 10;
    char v = 'C';
    myprintf("This is a number: %d and \nthis is a character: %c and \n another number: %d\n",a, v, b);
    return 0;
}

하지만 결과는 예상과 다릅니다!

This is a number: 1244780 and
this is a character: h and
another number: 29953463

내가 놓친 점은 무엇입니까 ??

도움이 되었습니까?

해결책

문제는 va_args와 함께 'printf'를 사용할 수 없다는 것입니다.당신은 사용해야합니다 vprintf 가변 인수 목록을 사용하는 경우.vprint, vsprintf, vfprintf 등(Microsoft의 C 런타임에는 버퍼 오버런 등을 방지하는 '안전한' 버전도 있습니다.)

샘플 작업은 다음과 같습니다.

void myprintf(char* fmt, ...)
{
    va_list args;
    va_start(args,fmt);
    vprintf(fmt,args);
    va_end(args);
}

int _tmain(int argc, _TCHAR* argv[])
{
    int a = 9;
    int b = 10;
    char v = 'C'; 
    myprintf("This is a number: %d and \nthis is a character: %c and \n another number: %d\n",a, v, b);
    return 0;
}

다른 팁

C++11에서는 다음을 사용하여 가능한 솔루션 중 하나입니다. Variadic templates:

template<typename... Args>
void myprintf(const char* fmt, Args... args )
{
    std::printf( fmt, args... ) ;
}

편집하다

@rubenvb가 지적했듯이 고려해야 할 장단점이 있습니다. 예를 들어 각 인스턴스에 대해 코드를 생성하면 코드가 팽창하게 됩니다.

그리고 순수하다는 말이 무슨 뜻인지 잘 모르겠습니다.

C++에서는 다음을 사용합니다.

#include <cstdarg>
#include <cstdio>

class Foo
{   void Write(const char* pMsg, ...);
};

void Foo::Write( const char* pMsg, ...)
{
    char buffer[4096];
    std::va_list arg;
    va_start(arg, pMsg);
    std::vsnprintf(buffer, 4096, pMsg, arg);
    va_end(arg);
    ...
}

실제로, 없는 함수를 호출하는 방법이 있습니다. va_list 래퍼의 버전입니다.아이디어는 어셈블러를 사용하고, 스택의 인수를 건드리지 않고, 함수 반환 주소를 임시로 바꾸는 것입니다.

Visual C x86의 예. call addr_printf 전화 printf():

__declspec( thread ) static void* _tls_ret;

static void __stdcall saveret(void *retaddr) {
    _tls_ret = retaddr;
}

static void* __stdcall _getret() {
    return _tls_ret;
}

__declspec(naked)
static void __stdcall restret_and_return_int(int retval) {
    __asm {
        call _getret
        mov [esp], eax   ; /* replace current retaddr with saved */
        mov eax, [esp+4] ; /* retval */
        ret 4
    }
}

static void __stdcall _dbg_printf_beg(const char *fmt, va_list args) {
    printf("calling printf(\"%s\")\n", fmt);
}

static void __stdcall _dbg_printf_end(int ret) {
    printf("printf() returned %d\n", ret);
}

__declspec(naked)
int dbg_printf(const char *fmt, ...)
{
    static const void *addr_printf = printf;
    /* prolog */
    __asm {
        push ebp
        mov  ebp, esp
        sub  esp, __LOCAL_SIZE
        nop
    }
    {
        va_list args;
        va_start(args, fmt);
        _dbg_printf_beg(fmt, args);
        va_end(args);
    }
    /* epilog */
    __asm {
        mov  esp, ebp
        pop  ebp
    }
    __asm  {
        call saveret
        call addr_printf
        push eax
        push eax
        call _dbg_printf_end
        call restret_and_return_int
    }
}

C나 C++를 사용하고 있나요?다음 C++ 버전인 C++0x에서는 다음을 지원합니다. 가변 템플릿 그 문제에 대한 해결책을 제공합니다.

다음과 같은 구문을 얻기 위해 영리한 연산자 오버로딩을 통해 또 다른 해결 방법을 얻을 수 있습니다.

void f(varargs va) {
    BOOST_FOREACH(varargs::iterator i, va)
        cout << *i << " ";
}

f(args = 1, 2, 3, "Hello");

이 작업을 수행하려면 클래스 varargs 재정의하려면 구현해야 합니다. operator = 이는 프록시 객체를 반환하고 이는 다시 재정의됩니다. operator ,.그러나 현재 C++에서 이 변형 유형을 안전하게 만드는 것은 유형 삭제를 통해 작동해야 하기 때문에 내가 아는 한 불가능합니다.

순수한 C/C++ 솔루션이란 무엇을 의미합니까?

나머지 매개변수(...)는 C 런타임에서 크로스 플랫폼을 지원합니다.

http://msdn.microsoft.com/en-us/library/kb57fad8.aspx

void myprintf(char* fmt, ...)
{
    va_ list args;
    va_ start(args,fmt);
    printf(fmt,args); ----> This is the fault. vprintf(fmt, args); should have been used.
    va_ end(args);
}
If you're just trying to call printf, 
there's a printf variant called vprintf that takes 
the va_list directly :  vprintf(fmt, args);
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top