2010-03-11 4 views
1

J'ai des fonctions que je souhaite appeler en fonction de certaines entrées. Chaque fonction a un nombre différent d'arguments. En d'autres termes,Appel de fonctions cdecl ayant un nombre différent d'arguments

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); 

Ceci est un peu volumineux et difficile à maintenir. Idéalement, ce sont des fonctions variadiques (par exemple, style printf) et peuvent utiliser des varargs. Mais ils ne le sont pas. Donc en exploitant la convention d'appel de cdecl, je bourre la pile via une structure complète de paramètres. Je me demande s'il y a une meilleure façon de le faire. Notez que ceci est strictement pour l'interne (par exemple, des outils simples, des tests unitaires, etc.) et ne sera pas utilisé pour tout code de production qui pourrait être soumis à des attaques malveillantes.

Exemple:

#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; 
} 

Sortie:

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

Quelle est votre question? –

+0

Je peux vous donner une réponse relativement sûre pour C++, mais pour C sauf si vous appelez des fonctions variadiques, vous ne pouvez pas garantir que chaque paramètre aura la même taille sur la pile. – MSN

+0

Les paramètres de la pile ne sont-ils pas cast/sauvegardés comme alignés sur la mémoire (par exemple, 32 bits, 64 bits) et sont donc de la même taille? – KlaxSmashing

Répondre

0

Plutôt que d'essayer de torturer ce hors des cas de coin dans la langue, je ferais cela d'une manière beaucoup plus simple, en définissant variadique fonctions d'encapsulation. Vous pouvez le faire génériquement avec des macros:

#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);         \ 
    } 

et macros similaires pour les autres chefs de arg. Ensuite, vous appelez:

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*) 

Cela définit un ensemble de fonctions avec les signatures suivantes que vous pouvez utiliser dans votre fonction de répartition:

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

Cela devrait être simple à partir de là.

Questions connexes