Domanda

Devo dichiarare un array di puntatori a funzioni simili:

extern void function1(void);
extern void function2(void);
...

void (*MESSAGE_HANDLERS[])(void) = {
   function1,
   function2,
   ...
};

Tuttavia, voglio che l'array sia dichiarato costante - sia i dati dell'array che il puntatore ai dati. Sfortunatamente, non ricordo dove posizionare le parole chiave const.

Suppongo che il puntatore reale, MESSAGE_HANDLERS in questo caso, sia già costante perché è dichiarato come un array. D'altra parte, i puntatori a funzione all'interno dell'array non possono essere modificati in fase di esecuzione se viene dichiarato come mostrato?

È stato utile?

Soluzione

Esiste una tecnica per ricordare come costruire questo tipo. Prima prova a leggere i puntatori a partire dal loro nome e leggi da destra a sinistra.

Come dichiarare quella roba senza aiuto?

Array

T t[5];

è un array di 5 T . Per rendere T un tipo di funzione, scrivi il tipo restituito a sinistra e i parametri a destra:

void t[5](void);

sarebbe essere un array di 5 funzioni che restituiscono nulla e non accettano parametri . Ma le funzioni in sé non possono essere inserite negli array! Non sono oggetti. Solo i puntatori a loro possono.

Che dire di

void * t[5](void);

Questo è ancora sbagliato in quanto cambierebbe solo il tipo di ritorno in un puntatore a vuoto. Devi usare le parentesi:

void (*t[5])(void);

e questo funzionerà davvero. t è un array di 5 puntatori a funzioni che restituiscono nulla e non accettano parametri .

Grande! Che dire di una serie di puntatori ad arras? È molto simile. Il tipo di elemento appare a sinistra e la dimensione a destra. Ancora una volta, sono necessarie le parentesi perché altrimenti l'array diventerebbe un array multidimensionale di puntatori interi:

int (*t[5])[3];

Questo è tutto! Un array di 5 puntatori ad array di 3 int .

E le funzioni?

Ciò che abbiamo appena appreso è vero anche per le funzioni. Dichiariamo una funzione che prende un int che restituisce un puntatore a un'altra funzione che non prende parametri e restituisce void:

void (*f(int))(void);

abbiamo bisogno di nuovo delle parentesi per lo stesso motivo di cui sopra. Ora potremmo chiamarlo e richiamare nuovamente la funzione restituita.

f(10)();

Restituzione di un puntatore alla funzione Restituzione di un altro puntatore alla funzione

Che dire di questo?

f(10)(true)(3.4);

? In altre parole, come apparirebbe una funzione int che restituisce un puntatore a una funzione che prende bool restituendo un puntatore a una funzione che prende il doppio e restituisce il vuoto ? La risposta è che li annidi e basta:

void (*(*f(int))(bool))(double);

Potresti farlo in tempi infiniti. In effetti, puoi anche restituire un puntatore a un array proprio come puoi fare con un puntatore a una funzione:

int (*(*f(int))(bool))[3];

Questa è una funzione che prende int restituendo un puntatore a una funzione che prende bool restituendo un puntatore a un array di 3 int

Cosa c'entra con const?

Ora che quanto sopra ha spiegato come costruire tipi più complessi da tipi fondamentali, puoi mettere const in luoghi in cui ora sai dove appartengono. Basta considerare:

T c * c * c ... * c name;

Il T è il tipo di base a cui puntiamo alla fine. Il c sta per const o no const. Ad esempio

int const * const * name;

dichiarerà il nome con il puntatore di tipo su un puntatore costante su una costante int . Puoi cambiare name , ma non puoi cambiare * name , che sarebbe di tipo

int const * const

e né ** name , che sarebbe di tipo

int const

Appliciamolo a un puntatore a funzione sopra:

void (* const t[5])(void);

Questo in realtà dichiarerebbe che l'array contiene puntatori costanti. Quindi, dopo aver creato (e inizializzato) l'array, i puntatori sono const, poiché il const è apparso dopo la stella. In questo caso non possiamo mettere una const prima della stella, poiché non ci sono puntatori a funzioni costanti . Le funzioni semplicemente non possono essere const in quanto ciò non avrebbe senso. Pertanto, non è valido quanto segue:

void (const * t[5])(void);

Conclusione

Il modo C ++ e C di dichiarare funzioni e array in realtà è un po 'confuso. Devi prima pensarci bene, ma se lo capisci, puoi scrivere dichiarazioni di funzioni molto compatte utilizzandolo.

Altri suggerimenti

cdecl dice:

cdecl> explain void (* const foo[])(void)
declare foo as array of const pointer to function (void) returning void

È quello che ti serve?

In situazioni come questa, fai un typedef per nominare la firma della tua funzione, il che rende molto più semplice:

typedef void MESSAGE_HANDLER(void);

con quello in atto, dovrebbe essere solo:

MESSAGE_HANDLER * const handlers[] = { function1, function2 };

Per ottenere il contenuto effettivo della costante dell'array.

EDIT : rimossa la parte del puntatore dal typedef , è davvero meglio (vivi e impara).

Con Visual Studio 2008, ottengo:

void (* const MESSAGE_HANDLERS[])(void) = {
   NULL,
   NULL
};

int main ()
{
    /* Gives error 
        '=' : left operand must be l-value
    */
    MESSAGE_HANDLERS = NULL;

    /* Gives error 
        l-value specifies const object
    */
    MESSAGE_HANDLERS[0] = NULL;
}

Non sono sicuro che funzionerà in 'C'. funziona in "C ++":

  • Per prima cosa definisci MESSAGE_HANDLERS come un tipo:

    typedef void (* MESSAGE_HANDLER) ();

  • Quindi, usa la definizione del tipo per dichiarare la tua matrice una costante:

    MESSAGE_HANDLER gestori const [] = {function1, function2};

Il trucco sta nel typedef , se puoi fare lo stesso semanticamente in 'C', dovrebbe funzionare anche.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top