2010-03-11 4 views
1

일부 입력에 따라 호출 할 함수가 있습니다. 각 함수의 인수 개수는 다릅니다. 즉,다른 수의 인수가있는 cdecl 함수 호출

if (strcmp(str, "funcA") == 0) funcA(a, b, c); 
else if (strcmp(str, "funcB") == 0) funcB(d); 
else if (strcmp(str, "funcC") == 0) funcC(f, g); 

이것은 약간 부피가 커서 유지하기 어렵습니다. 이상적으로는 가변 인자 함수 (예 : printf 스타일)이며 varargs를 사용할 수 있습니다. 그러나 그들은 그렇지 않습니다. 그래서 cdecl 호출 규칙을 악용하여 구조체를 통해 스택을 채우고 있습니다. 더 좋은 방법이 있는지 궁금하네요. 이는 사내 (예 : 단순 도구, 단위 테스트 등)를위한 것이며 악의적 인 공격을받을 수있는 프로덕션 코드에는 사용되지 않습니다.

예 :

#include <stdio.h> 

typedef struct __params 
{ 
    unsigned char* a; 
    unsigned char* b; 
    unsigned char* c; 
} params; 

int funcA(int a, int b) 
{ 
    printf("a = %d, b = %d\n", a, b); 
    return a; 
} 

int funcB(int a, int b, const char* c) 
{ 
    printf("a = %d, b = %d, c = %s\n", a, b, c); 
    return b; 
} 

int funcC(int* a) 
{ 
    printf("a = %d\n", *a); 
    *a *= 2; 
    return 0; 
} 

typedef int (*f)(params); 

int main(int argc, char**argv) 
{ 
    int val; 
    int tmp; 
    params myParams; 
    f myFuncA = (f)funcA; 
    f myFuncB = (f)funcB; 
    f myFuncC = (f)funcC; 

    myParams.a = (unsigned char*)100; 
    myParams.b = (unsigned char*)200; 

    val = myFuncA(myParams); 
    printf("val = %d\n", val); 

    myParams.c = (unsigned char*)"This is a test"; 
    val = myFuncB(myParams); 
    printf("val = %d\n", val); 

    tmp = 300; 
    myParams.a = (unsigned char*)&tmp; 
    val = myFuncC(myParams); 
    printf("a = %d, val = %d\n", tmp, val); 
    return 0; 
} 

출력 :

gcc -o func func.c 
./func 
a = 100, b = 200 
val = 100 
a = 100, b = 200, c = This is a test 
val = 200 
a = 300 
a = 600, val = 0 
+1

무엇이 질문입니까? –

+0

C++에 대해서는 비교적 안전한 대답을 줄 수 있지만 가변 인수 함수를 호출하지 않는 한 모든 매개 변수의 스택 크기가 동일하지는 않습니다. – MSN

+0

스택의 매개 변수가 메모리 정렬 방식 (예 : 32 비트, 64 비트)으로 캐스팅/저장되지 않으므로 크기가 동일합니까? – KlaxSmashing

답변

0

오히려 언어로 코너 케이스에서이 고문하는 것보다, 나는 가변을 정의하여, 훨씬 더 간단한 방법이 할 것 랩퍼 기능. 당신은 매크로 일반적으로이 작업을 수행 할 수 있습니다 다른 인수 개수에 대한

#define WRAP_VARIADIC_2_ARG(FNAME, RETTYPE, ARGTYPE1, ARGTYPE2) \ 
    (RETTYPE) wrapped_##FNAME(...) {        \ 
    va_list args;            \ 
    va_start(args, 2);           \ 
    (ARGTYPE1) arg1 = va_arg(args, (ARGTYPE1));     \ 
    (ARGTYPE2) arg2 = va_arg(args, (ARGTYPE2));     \ 
    va_end(args);            \ 
    return FNAME(arg1, arg2);         \ 
    } 

와 유사한 매크로를. 그런 다음 전화 :

WRAP_VARIADIC_2_ARG(funcA, int, int, int) 
WRAP_VARIADIC_3_ARG(funcB, int, int, int, const char*) 
WRAP_VARIADIC_1_ARG(funcC, int, int*) 

이것은 당신이 당신 발송 기능에서 사용할 수있는 다음과 같은 서명을 함수의 집합을 정의합니다 :

int wrapped_funcA(...) 
int wrapped_funcB(...) 
int wrapped_funcC(...) 

이 거기에서 간단합니다.