Wie deklariert man ein Array von konstanten Funktionszeigern in C?

Lesezeit: 6 Minuten

Benutzer-Avatar
Richter Maygarden

Ich muss ein Array von Zeigern auf Funktionen wie folgt deklarieren:

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

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

Ich möchte jedoch, dass das Array als Konstante deklariert wird – sowohl die Daten im Array als auch der Zeiger auf die Daten. Leider weiß ich nicht mehr, wo ich die const-Schlüsselwörter platzieren soll.

Ich gehe davon aus, dass der eigentliche Zeiger, in diesem Fall MESSAGE_HANDLERS, bereits konstant ist, da er als Array deklariert ist. Könnten andererseits die Funktionszeiger innerhalb des Arrays nicht zur Laufzeit geändert werden, wenn es wie gezeigt deklariert ist?

Benutzer-Avatar
Johannes Schaub – litb

Es gibt eine Technik, um sich daran zu erinnern, wie man einen solchen Typ erstellt. Versuchen Sie zunächst, Zeiger ausgehend von ihrem Namen zu lesen und von rechts nach links zu lesen.

Wie kann man das Zeug ohne Hilfe deklarieren?

Arrays

T t[5];

ist ein Reihe von 5 T. Um T zu einem Funktionstyp zu machen, schreiben Sie den Rückgabetyp nach links und die Parameter nach rechts:

void t[5](void);

möchten Bohne Array von 5 Funktionen, die void zurückgeben und keine Parameter annehmen. Aber Funktionen selbst können nicht in Arrays gefüllt werden! Sie sind keine Objekte. Nur Zeiger auf sie können.

Wie wäre es mit

void * t[5](void);

Das ist immer noch falsch, da es nur den Rückgabetyp in einen Zeiger auf void ändern würde. Sie müssen Klammern verwenden:

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

und das wird tatsächlich funktionieren. t ist ein Array von 5 Zeigern auf Funktionen, die void zurückgeben und keine Parameter annehmen.

Groß! Was ist mit einem Array von Zeigern auf Arras? Das ist sehr ähnlich. Der Elementtyp wird links und die Dimension rechts angezeigt. Auch hier sind Klammern erforderlich, da das Array sonst zu einem mehrdimensionalen Array von Integer-Zeigern werden würde:

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

Das ist es! Ein Array von 5 Zeiger auf Arrays von 3 int.

Was ist mit Funktionen?

Was wir gerade gelernt haben, gilt auch für Funktionen. Lassen Sie uns eine Funktion deklarieren, die einen int nimmt, der einen Zeiger auf eine andere Funktion zurückgibt, die keinen Parameter hat und void zurückgibt:

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

Wir brauchen wieder Klammern aus dem gleichen Grund wie oben. Wir könnten es jetzt aufrufen und die zurückgegebene Funktion, auf die verwiesen wird, erneut aufrufen.

f(10)();

Zurückgeben eines Zeigers auf eine Funktion Zurückgeben eines anderen Zeigers auf eine Funktion

Was ist damit?

f(10)(true)(3.4);

? Mit anderen Worten, wie würde a Funktion nimmt int, gibt einen Zeiger auf eine Funktion zurück, nimmt bool, gibt einen Zeiger auf eine Funktion zurück, nimmt double und gibt void zurück würde aussehen wie? Die Antwort ist, dass Sie sie einfach verschachteln:

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

Das könntest du unendlich oft tun. Tatsächlich können Sie einen Zeiger auf ein Array genauso zurückgeben wie einen Zeiger auf eine Funktion:

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

Das ist ein Funktion nimmt int und gibt einen Zeiger auf eine Funktion zurück, die bool nimmt und einen Zeiger auf ein Array von 3 int zurückgibt

Was hat das mit const zu tun?

Nachdem oben erklärt wurde, wie man komplexere Typen aus grundlegenden Typen aufbaut, können Sie setzen const an Orten, wo Sie jetzt wissen, wo sie hingehören. Bedenke nur:

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

Das T ist der Grundtyp, auf den wir am Ende verweisen. Das c steht entweder für const oder not const. Zum Beispiel

int const * const * name;

wird deklarieren, dass name den Typ hat Zeiger auf eine Konstante Zeiger auf eine Konstante int. Du kannst ändern nameaber Sie können nicht ändern *namewas vom Typ wäre

int const * const

und weder **namewas vom Typ wäre

int const

Wenden wir dies auf einen Funktionszeiger von oben an:

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

Dies würde das Array tatsächlich so deklarieren, dass es konstante Zeiger enthält. Nach dem Erstellen (und Initialisieren) des Arrays wird die Zeiger sind konstant, weil die const erschien nach dem Stern. Beachten Sie, dass wir kein a setzen können const vor dem Stern in diesem Fall, da es gibt keine Zeiger auf konstante Funktionen. Funktionen können einfach nicht konstant sein, da dies keinen Sinn machen würde. Also gilt folgendes nicht:

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

Fazit

Die Deklaration von Funktionen und Arrays in C++ und C ist eigentlich etwas verwirrend. Man muss sich erst einmal damit beschäftigen, aber wenn man es versteht, kann man damit sehr kompakte Funktionsdeklarationen schreiben.

  • Es tut mir leid, Kumpel. anfangs hatte ich const drin, aber irgendwie habe ich es entfernt. es ist jetzt wieder drin, ich habe es erweitert, um es genauer zu erklären.

    – Johannes Schaub – litb

    4. Dezember 2008 um 3:20 Uhr

  • Vielen Dank! Das ist eine großartige Erklärung.

    – uckelmann

    1. November 2010 um 15:46 Uhr

Benutzer-Avatar
entspannen

In solchen Situationen tun Sie a typedef um Ihre Funktionssignatur zu benennen, das macht es viel einfacher:

typedef void MESSAGE_HANDLER(void);

damit sollte es nur sein:

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

Um den tatsächlichen Inhalt der Array-Konstante zu erhalten.

BEARBEITEN: Zeigerteil aus dem entfernt typedefdas ist wirklich besser (leben und lernen).

  • Ich bin mir nicht sicher, aber Sie sollten das Schlüsselwort const wahrscheinlich nach MASSAGE_HANDLER platzieren. Wie auch immer, diese Antwort sollte höher sein, Typedefs sind der Weg, um Verwirrung zu vermeiden!

    – Vinzenz

    18. März 2016 um 10:09 Uhr

  • @Vincent T const und const T gleich sind (wobei T ein Bezeichner ist, der einen Typ identifiziert). Da hast du Recht T const wird von vielen als konsequenter angesehen.

    – MM

    19. Mai 2017 um 11:49 Uhr

  • Beachten Sie, dass viele Leute Pointer Typedefs als etwas verwirrend betrachten; Sie müssen den Zeiger hier nicht in die Typedef aufnehmen, z typedef void Handler(void); Handler func1, func2; Handler * const handlers[] = { func1, func2 }; .

    – MM

    19. Mai 2017 um 11:51 Uhr

cdecl sagt:

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

Ist es das, was Sie brauchen?

  • Ja, genau das wurde ich gebraucht. Ich war mir der Programme cdecl (und c++decl) nicht bewusst. Danke für den Tipp.

    – Richter Maygarden

    3. Dezember 2008 um 15:47 Uhr

  • cdecl ist ausgezeichnet. Danke, dass du es in das SO-Wissen gebracht hast.

    – David

    19. Juli 2010 um 19:08 Uhr

Mit VisualStudio 2008 erhalte ich:

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

Benutzer-Avatar
Curro

Ich bin mir nicht sicher, ob dies in ‘C’ funktioniert. es funktioniert in ‘C++’:

  • Definieren Sie zunächst MESSAGE_HANDLERS als Typ:

    typedef void (*MESSAGE_HANDLER)();

  • Verwenden Sie dann die Typdefinition, um Ihr Array als Konstante zu deklarieren:

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

Der Trick liegt in der typedefwenn Sie dasselbe semantisch in ‘C’ tun können, sollte es auch funktionieren.

  • Deklariert dies nicht ein Array von Zeigern auf konstante Funktionen?

    – Erich

    11. September 2017 um 17:05 Uhr

  • Deklariert dies nicht ein Array von Zeigern auf konstante Funktionen?

    – Erich

    11. September 2017 um 17:05 Uhr

1354610cookie-checkWie deklariert man ein Array von konstanten Funktionszeigern in C?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy