www.mikrocontroller.net

Forum: Compiler & IDEs funktionen und pointer darauf... ?


Autor: Stefan Sczekalla (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Chris (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Stefan Sczekalla (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Chris (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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).

Autor: Werner B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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 ...

Autor: Jörg Wunsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Anmerkung: int8_t und Konsorten sind via <inttypes.h> im C99-Standard
genormt.

Autor: Stefan Sczekalla (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Chris (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Das heist eine Pointer auf eine paramelterlose Funktion die nichts
> zurückgibt würde so deffiniert ?
>
> typedef void (*zeiger)(void);

Genau.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.