Hi, ich moechte einige functions schreiben, die ich dann über einen "index" aufrufen möchte. ich bin nun leider nicht wirklich sattelfest was funcionpointer etc. betrifft und der kernigham war mit zwei seiten nicht wirklich erleuchtend .... wie bekomme ich denn die "startadresse" der funktion(en) in eine Tabelle und wie "call"e ich dann die Funktion deren addresse an Stelle "i" in der dem Pointerarray steht. vielen Dank im Voraus, Stefan
Am einfachsten und übersichtlichsten geht's mit einem typedef: typedef int (*fptr)(int); /* "zeigt auf eine Funktion, die int übernimmt und int zurückgibt" */ int foo(int i) { return i*2; } int bar(int i) { return i*3; } int baz(int i) { return i*4; } fptr array[3] = { &foo, &bar, &baz }; /* ... */ for(i = 0; i < 3; ++i) array[i](1); /* jede Funktion aus dem Array wird einmal aufgerufen, Parameter ist jedesmal 1 */ In C++ geht das so ziemlich sicher, in C müsste es eigentlich auch gehen.
Hallo cris, Also ich habe den Code mal eingbaut und Kompiliert. dann hab ich mir noch den Kernighan geschnappt und nachgelesen. Also Fehlermeldung gibts keine - aber woher weiß ich den das der pointer auf ein Funktion ein "int" lang ist ? - oder inerpretiere ich den typedef falsch ? ich meine gut, es wäre logisch wegen des Prozessors ( addresierung eines ljmp ) - aber meine logik muss da ja nicht die des Kompilerbauers sein ... ( seuftz - ja ich bin nicht wirklich fitt in C ) Grüße, Stefan
> Also Fehlermeldung gibts keine - aber woher weiß ich den das der > pointer auf ein Funktion ein "int" lang ist ? - oder inerpretiere ich > den typedef falsch ? Jep, tust du. Kurze Erklärung: Die ints im typedef sagen nur etwas über die Signatur der Funktion aus, auf die der Zeiger zeigt. Lange Erklärung: Das typedef sieht ja so aus: typedef int (*fptr)(int); Lassen wir mal das * weg und nennen fptr in f um: typedef int (f)(int); Die Klammern um f kann man sich dann natürlich auch schenken: typedef int f(int); So, das sieht nun beinahe wie ein ganz gewöhnlicher Funktionsprototyp aus, abgesehen vom typedef davor. Der Typ f bezeichnet hier eine Funktion selbst, keinen Zeiger darauf. Dieser Typ ist damit genauso abstrakt wie void, man kann keine Variable vom Typ f erstellen. Was man aber darf, ist folgendes: f* p; p ist jetzt ein Zeiger auf eben die Funktion, deren Prototyp ("Signatur") ich oben "getypedeft" habe. Man kann nun also ohne weiteres die beiden letzen Zeilen kombinieren: typedef int f(int); typedef f* fptr; Damit deklariert man den Typ fptr unmissverständlich als Funktionszeiger. Jetzt möchte man aber gerne nur ein typedef haben, also wird eingesetzt: typedef int (int)* fptr; /* oberes typedef stur ins untere eingesetzt */ Das ist aber totaler Blödsinn, die Parameter gehören immer ans Ende: typedef int * fptr (int); Aber halt! Gerade eben noch hatten wir: typedef int f(int); als abstraktes Funktionsobjekt definiert. Was ist jetzt typedef int* fptr (int); für den Compiler? Natürlich genauso ein abstraktes Funktionsobjekt. Nur diesmal liefert die so spezifierte Funktion einen int* zurück. Aus genau diesem Grund muss man so ungewohnte Klammern setzen: typedef int (*fptr)(int); Jetzt muss auch der letzte Compiler akzeptieren, dass man hier einen Zeiger deklariert, kein abstraktes Funktionstypedef. Und zwar einen Zeiger auf eine Funktion, die a) einen int zurückliefert und b) einen int übernimmt. Funktionszeiger sind in C (und in C++ noch stärker) ein völlig eigener Typ. Funktionszeiger werden in C++ (und ich denke auch in C) strikt von Datenzeigern getrennt behandelt. char*, int*, das sind alles Datenzeiger. void* ist in diesem Sinne aber auch ein Datenzeiger und damit nicht kompatibel zu Funktionszeigern. Funktionszeiger können nämlich größer sein als void* (in C++ sind sie es auch häufig). In C könnte es z.B. passieren, dass du eine Maschine hast, die viel mehr Programmspeicher als RAM hat. Dann hat ein void* vielleicht nur 16 Bit, ein Funktionszeiger aber 24 (rein hypothetisch). Das wäre mit dem C-Standard ohne weiteres vereinbar, führt bei unsauberer Programmierung aber schnell zu Fehlern. Einen Funktionszeiger speichert man daher korrekterweise niemals in einem void*. Ein int muss sowieso nicht groß genug für einen Zeiger sein, egal ob Daten- oder Funktionszeiger. Bei 64-Bit-Rechnern etwa hat ein int immer noch 32 Bit, ein Zeiger aber 64 Bit (beim Visual C++ Compiler).
Das mit der länge eines datentyps ist generell compilerabhängig. Der standard (ANSI C) definiert nur eine mindestlänge die ein datentyp haben muss. Darum gibt es auch so viele macros, die abhängig vom verwendeten compiler eigene "längen"-datentypen definieren. Die geschieht um die portabilität von sourcecode zwischen den verschiedenen compilern zu gewährleisten. z.b. int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t ...
Anmerkung: int8_t und Konsorten sind via <inttypes.h> im C99-Standard genormt.
Hallo Chris, vielen Dank für die ausführliche Erklärung. Das heist eine Pointer auf eine paramelterlose Funktion die nichts zurückgibt würde so deffiniert ? typedef void (*zeiger)(void); ... und dabei weiss dann der Compiler, das er einen "Abstrakten" Zeiger als "neuen" Typ anlegt. Wie groß der sein muss verhackstückt der Compiler intern. Grüße, Stefan
> Das heist eine Pointer auf eine paramelterlose Funktion die nichts > zurückgibt würde so deffiniert ? > > typedef void (*zeiger)(void); Genau.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.