2013-05-27 7 views
9

Ich habe zwei Funktionen mit variabler Anzahl und Arten von ArgumentenFunktionszeiger auf verschiedene Funktionen mit unterschiedlichen Argumenten in C

double my_func_one(double x, double a, double b, double c) { return x + a + b + c } 
double my_func_two(double x, double p[], double c) { return x + p[0] + p[1] + c } 

Ich mag die Funktionen einen Zeiger auf eine Funktion verwenden, ich auf einem etwas über basierend definiert Bedingung wird wahr, z

Meine Frage ist, für dieses Szenario, kann ich überhaupt einen Funktionszeiger definieren? Wenn ja, wie?
Mein Verständnis ist, dass der Prototyp des Funktionszeigers für alle Funktionen identisch sein sollte, auf die er gezeigt werden kann.

typedef double (*pfunction)(int, int); 

In meinem Fall sind sie nicht das Gleiche. Gibt es einen anderen Weg, dies zu tun?

Sprache

ich in C entwickle und ich bin mit gcc 4.4.3 Compiler/Linker

+1

die Funktion Machen Sie einen 'void * Zeiger', und führen Sie dann die richtige Schublade gesteckt, wenn sie aufgerufen werden? Sie verlieren jedoch alle Arten von Typ-Sicherheit. –

Antwort

9

Meine Frage ist, für dieses Szenario ist, kann ich überhaupt einen Funktionszeiger definieren?

No. (andere als die durch schmutzige Schublade gesteckt.)

Gibt es eine andere Möglichkeit, dies zu tun?

Ihre beste Wette ist es, eine Wrapper-Funktion für eine Ihrer vorhandenen Funktionen zu erstellen. Zum Beispiel:

double my_func_one_wrapper(double x, double p[], double c) { 
    return my_func_one(x, p[0], p[1], c); 
} 

Auf diese Weise haben Sie zwei Funktionen mit der gleichen Signatur und damit den gleichen Funktionszeiger.

+0

Danke @Oli Charlesworth und alle anderen für ihre wirklich schnellen Antworten. – fahad

1

Ihr Verständnis ist wahr.
Die Signatur Ihres Funktionszeigers muss mit der/den entsprechenden Funktion (en) übereinstimmen.

Betrachten learncpp.com:

Genau wie es möglich ist, einen nicht konstanten Zeiger auf eine Variable zu deklarieren, ist es auch möglich,> einen nicht konstanten Zeiger auf eine Funktion deklarieren. Die Syntax dafür ist so eine der hässlichsten Dinge> Sie jemals sehen:

// pFoo is a pointer to a function that takes no arguments and returns an integer 
int (*pFoo)(); 

Die Klammern um * pFoo notwendig sind, um den Vorrang Gründen als int *pFoo() würde als Funktion pFoo genannt interpretiert werden Das nimmt keine Parameter und gibt einen Zeiger auf eine Ganzzahl zurück.

Im obigen Snippet ist ein Zeiger auf eine Funktion, die keine Parameter enthält und eine ganze Zahl zurückgibt. pFoo kann auf jede Funktion "zeigen", die dieser Signatur entspricht.

...

Beachten Sie, dass die Signatur (Parameter und Rückgabewert) des Funktionszeigers mit der Signatur der Funktion übereinstimmen muss.

+1

Dies beantwortet nicht wirklich die Frage ... –

+0

Korrigiert meinen Beitrag –

1

Was Sie wollen, ist möglich, aber ein bisschen schmutzig. Funktionszeiger können ineinander umgewandelt werden, ohne Informationen zu verlieren. Wichtig ist, dass Sie immer eine Funktion über einen solchen Zeiger nur mit einer Signatur aufrufen müssen, die seiner Definition entspricht. Also wenn Sie zurückwerfen, bevor Sie die Funktion (en) aufrufen und mit den richtigen Argumenten aufrufen, sollte alles in Ordnung sein.

14

Der sauberste Weg, es zu tun ist, eine Vereinigung nutzen:

typedef union { 
    double (*func_one)(double x, double a, double b, double c); 
    double (*func_two)(double x, double p[], double c); 
} func_one_two; 

Dann können Sie eine Instanz der Vereinigung initialisieren, und enthalten Informationen zur swap_function Funktion zu sagen, welches Feld gültig ist:

func_one_two func; 

if (condition_1) 
    func.func_one = my_func_one; 
else if (condition_2) 
    func.func_two = my_func_two; 

// The function that will use the function I passed to it 
swap_function(a, b, func, condition_1); 

Dies setzt voraus, dass swap_function basierend auf condition_1, false bekannt sein kann, dass es condition_2 annehmen sollte. Beachten Sie, dass die Union nach Wert übergeben wird. es ist schließlich nur ein Funktionszeiger in der Größe, also ist es nicht teurer als einen Zeiger darauf zu übergeben.

-2

Ein Beispiel für den Typecasting-Ansatz zur Verwendung eines gleichen Funktionszeigers für verschiedene Funktionen verschiedener Prototypen. <>

#include <stdio.h> 
typedef void (*myFuncPtrType) (void); 

typedef int (*myFunc2PtrType)(int, int); 

typedef int * (*myFunc3PtrType)(int *); 

static void myFunc_1 (void); 
static int myFunc_2 (int, int); 
static int* myFunc_3 (int *); 

const myFuncPtrType myFuncPtrA[] = { 
            (myFuncPtrType)myFunc_1, 
            (myFuncPtrType)myFunc_2, 
            (myFuncPtrType)myFunc_3 
}; 

static void myFunc_1 (void) 
{ 
    printf("I am in myFunc_1 \n"); 
} 

static int myFunc_2 (int a, int b) 
{ 
    printf("I am in myFunc_2\n"); 
    return (a+b); 
} 

static int* myFunc_3 (int *ptr) 
{ 
    printf("I am in myFunc_3\n"); 
    *ptr = ((*ptr) * 2); 
    return (ptr+1); 
} 

int main(void) { 
    // your code goes here 
    int A[2],C; 

    int* PTR = A; 

    (*(myFuncPtrA[0]))(); 

    A[0]=5; 
    A[1]=6; 

    C = ((myFunc2PtrType)(*(myFuncPtrA[1])))(A[0],A[1]); 

    printf("Value of C: %d \n", C); 

    printf("Value of PTR before myFunc_3: %p \n", PTR); 
    printf("Value of *PTR before myFunc_3: %d \n", *PTR); 

    PTR = ((myFunc3PtrType)(*(myFuncPtrA[2])))(&A); 

    //Lets look how PTR has changed after the myFunc_3 call 

    printf("Value of PTR after myFunc_3: %p \n", PTR); 
    printf("Value of *PTR after myFunc_3: %d \n", *PTR); 


    return 0; 
} 
+1

Könnten Sie bitte eine Beschreibung von dem, was Sie getan haben, hinzufügen? Anstatt nur den Code einzufügen. – kaldoran

Verwandte Themen