그래서 나는 둘 다 비슷한 인수를 갖는 2 개의 함수를 가지고 있습니다.
void example(int a, int b, ...);
void exampleB(int b, ...);
이제를 example
호출 exampleB
하지만 수정하지 않고 변수 인수 목록의 변수를 어떻게 전달할 수 있습니까 exampleB
(이미 다른 곳에서도 사용됨).
그래서 나는 둘 다 비슷한 인수를 갖는 2 개의 함수를 가지고 있습니다.
void example(int a, int b, ...);
void exampleB(int b, ...);
이제를 example
호출 exampleB
하지만 수정하지 않고 변수 인수 목록의 변수를 어떻게 전달할 수 있습니까 exampleB
(이미 다른 곳에서도 사용됨).
답변:
직접 할 수는 없습니다. 다음을받는 함수를 만들어야합니다 va_list
.
#include <stdarg.h>
static void exampleV(int b, va_list args);
void exampleA(int a, int b, ...) // Renamed for consistency
{
va_list args;
do_something(a); // Use argument a somehow
va_start(args, b);
exampleV(b, args);
va_end(args);
}
void exampleB(int b, ...)
{
va_list args;
va_start(args, b);
exampleV(b, args);
va_end(args);
}
static void exampleV(int b, va_list args)
{
...whatever you planned to have exampleB do...
...except it calls neither va_start nor va_end...
}
, ...
서명에 포함 된 변수 인수 목록을 사용하는 함수에 대한 명명 된 첫 번째 인수가 필요합니다 . 변수 인수를으로 변환 한 경우 va_list
를를받는 va_list
다른 함수에 전달할 수 va_list
있지만 해당 함수 (또는 호출하는 함수)는 va_list
.
아마도 여기 연못에 바위를 던질 수 있지만 C ++ 11 가변 템플릿으로 꽤 괜찮은 것 같습니다.
#include <stdio.h>
template<typename... Args> void test(const char * f, Args... args) {
printf(f, args...);
}
int main()
{
int a = 2;
test("%s\n", "test");
test("%s %d %d %p\n", "second test", 2, a, &a);
}
최소한 g++
.
args...
또한 printf를 감싸고 싶었고 여기에서 유용한 답변을 찾았습니다.
가변 개수의 인수를 printf / sprintf에 전달하는 방법
저는 성능에 전혀 관심이 없었습니다 (이 코드는 여러 가지 방법으로 개선 될 수 있다고 확신합니다. 자유롭게 수행 할 수 있습니다. :)), 이것은 일반적인 디버그 인쇄에만 해당하므로 이렇게했습니다.
//Helper function
std::string osprintf(const char *fmt, ...)
{
va_list args;
char buf[1000];
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args );
va_end(args);
return buf;
}
그런 다음 이렇게 사용할 수 있습니다
Point2d p;
cout << osprintf("Point2d: (%3i, %3i)", p.x, p.y);
instead of for example:
cout << "Point2d: ( " << setw(3) << p.x << ", " << p.y << " )";
C ++ ostream은 일부 측면에서 아름답지만 숫자 사이에 괄호, 콜론 및 쉼표와 같은 작은 문자열을 삽입하여 이와 같은 것을 인쇄하려는 경우 실제로 끔찍합니다.
부수적으로 많은 C 구현에는 IMHO가 C 표준의 일부 여야하는 내부 v? printf 변형이 있습니다. 정확한 세부 사항은 다양하지만 일반적인 구현은 문자 출력 함수 포인터와 발생해야 할 일을 알려주는 정보를 포함하는 구조체를 허용합니다. 이렇게하면 printf, sprintf 및 fprintf가 모두 동일한 '코어'메커니즘을 사용할 수 있습니다. 예를 들어, vsprintf는 다음과 같을 수 있습니다.
무효 s_out (PRINTF_INFO * p_inf, char ch) { (* (p_inf-> destptr) ++) = ch; p_inf-> result ++; } int vsprintf (char * dest, const char * fmt, va_list args) { PRINTF_INFO p_inf; p_inf.destptr = 대상; p_inf.result = 0; p_inf.func = s_out; core_printf (& p_inf, fmt, args); }
core_printf 함수는 출력 할 각 문자에 대해 p_inf-> func를 호출합니다. 그런 다음 출력 함수는 문자를 콘솔, 파일, 문자열 또는 다른 것으로 보낼 수 있습니다. 구현이 core_printf 함수 (및 사용하는 설정 메커니즘)를 노출하면 모든 종류의 변형으로 확장 할 수 있습니다.
래핑 vsprintf
하고 있으며 이것이 C ++로 태그가 지정되어 있다는 주석을 기반 으로이 작업을 시도하지 않고 대신 C ++ iostreams를 사용하도록 인터페이스를 변경하는 것이 좋습니다. print
유형 안전 및 printf
처리 할 수없는 항목을 인쇄 할 수있는 것과 같은 기능 라인에 비해 이점 이 있습니다. 일부 재 작업은 향후 상당한 고통을 덜어 줄 수 있습니다.
이것이 유일한 방법이고 .. 최선의 방법이기도하다 ..
static BOOL(__cdecl *OriginalVarArgsFunction)(BYTE variable1, char* format, ...)(0x12345678); //TODO: change address lolz
BOOL __cdecl HookedVarArgsFunction(BYTE variable1, char* format, ...)
{
BOOL res;
va_list vl;
va_start(vl, format);
// Get variable arguments count from disasm. -2 because of existing 'format', 'variable1'
uint32_t argCount = *((uint8_t*)_ReturnAddress() + 2) / sizeof(void*) - 2;
printf("arg count = %d\n", argCount);
// ((int( __cdecl* )(const char*, ...))&oldCode)(fmt, ...);
__asm
{
mov eax, argCount
test eax, eax
je noLoop
mov edx, vl
loop1 :
push dword ptr[edx + eax * 4 - 4]
sub eax, 1
jnz loop1
noLoop :
push format
push variable1
//lea eax, [oldCode] // oldCode - original function pointer
mov eax, OriginalVarArgsFunction
call eax
mov res, eax
mov eax, argCount
lea eax, [eax * 4 + 8] //+8 because 2 parameters (format and variable1)
add esp, eax
}
return res;
}