C Language Migliori pratiche

Esempio

Usando typedef

Potrebbe essere utile usare un typedef invece di dichiarare il puntatore funzione ogni volta a mano.

La sintassi per la dichiarazione di typedef per un puntatore a funzione è:

typedef returnType (*name)(parameters);

Esempio:

Positivo che abbiamo una funzione, sort , che si aspetta un puntatore a una funzione compare tale che:

compare - Una funzione di confronto per due elementi che deve essere fornita ad una funzione di ordinamento.

"compare" dovrebbe restituire 0 se i due elementi sono considerati uguali, un valore positivo se il primo elemento passato è "più grande" in un certo senso rispetto al secondo elemento e altrimenti la funzione restituisce un valore negativo (il che significa che il primo elemento è "minore" rispetto al secondo).

Senza un typedef passeremmo un puntatore a funzione come argomento a una funzione nel modo seguente:

void sort(int (*compare)(const void *elem1, const void *elem2)) { 
    /* inside of this block, the function is named "compare" */
}

Con un typedef , scriveremmo:

typedef int (*compare_func)(const void *, const void *);

e quindi potremmo cambiare la firma della funzione di sort a:

void sort(compare_func func) { 
    /* In this block the function is named "func" */
}

entrambe le definizioni di sort accettano qualsiasi funzione della forma

int compare(const void *arg1, const void *arg2) {
    /* Note that the variable names do not have to be "elem1" and "elem2" */
}

I puntatori di funzione sono l'unico posto in cui devi includere la proprietà del puntatore del tipo, ad esempio non provare a definire tipi come typedef struct something_struct *something_type . Ciò vale anche per una struttura con membri a cui non si deve accedere direttamente dai chiamanti API, ad esempio il tipo FILE stdio.h (che come si vedrà ora non è un puntatore).

Prendendo indicatori di contesto.

Un puntatore a funzione dovrebbe quasi sempre prendere un vuoto fornito dall'utente * come puntatore del contesto.

Esempio

/* function minimiser, details unimportant */
double findminimum( double (*fptr)(double x, double y, void *ctx), void *ctx)
{
    ...
    /* repeatedly make calls like this */
    temp = (*fptr)(testx, testy, ctx);
}

/* the function we are minimising, sums two cubics */
double *cubics(double x, double y, void *ctx)
{
    double *coeffsx = ctx;
    double *coeffsy = coeffx + 4;

    return coeffsx[0] * x * x * x + coeffsx[1] * x * x + coeffsx[2] * x + coeffsx[3] +
           coeffsy[0] * y * y * y + coeffsy[1] * y * y + coeffsy[2] * y + coeffsy[3];

} 

void caller()
{
    /* context, the coefficients of the cubics */
    double coeffs[8] = {1, 2, 3, 4, 5, 6, 7, 8};
    double min;

    min = findminimum(cubics, coeffs);       
}

L'uso del puntatore del contesto significa che i parametri aggiuntivi non devono essere codificati nella funzione puntata o richiedono l'uso globale.

La funzione di libreria qsort() non segue questa regola e spesso si può andare via senza contesto per funzioni di confronto banali. Ma per qualcosa di più complicato, il puntatore del contesto diventa essenziale.


Guarda anche

Funzioni puntatori