Forum: PC-Programmierung Frage zu Funktionspointern


von WiesentM (Gast)


Lesenswert?

Hallo zusammen,

ich habe mal eine Frage zu Funktionspointern. Programmiersprache ist C.
1
typedef struct{
2
   int a;
3
}test_a_t;
4
5
typedef struct{
6
   double b;
7
}test_b_t;
8
9
void test_1_func(test_a_t *);
10
void test_2_func(test_b_t *);
11
12
void (*f_ptr[2])(void *) = {test_1_func, test_2_func}; 
13
14
void test_1_func(test_a_t *i){
15
   // hier ein bisschen Code
16
}
17
18
void test_2_func(test_a_t *i){
19
   // hier ein bisschen Code
20
}

Würde dieser Code funktionieren? Der Compiler gibt mir eine Warnung 
wegen des übergebenen Typs aus. Aber der Typ ist ja jeweils ein Pointer.

Ist es überhaupt möglich ein Array aus Funktionszeigern zu erstellen, 
wobei die Funktionen andere Übergabetypen haben? Die Anzahl der 
Übergabeparameter ist allerdings immer gleich. Soll immer ein Zeiger 
sein, aber eben jeweil ein anderer Typ.

Mfg Michael

von Sven P. (Gast)


Lesenswert?

WiesentM schrieb:
> Ist es überhaupt möglich ein Array aus Funktionszeigern zu erstellen,
> wobei die Funktionen andere Übergabetypen haben?
Durch die Aufrufkonvention von C ist das machbar, ja. Andernfalls würden 
die Funktionen mit variabler Parameterliste ('variadic', also das Zeugs 
mit va_list und '...' im Prototypen) ja auch nicht funktionieren. Das 
läuft auf eine leere Parameterliste im Prototypen hinaus.

Was nicht geht, ist, Funktionszeiger und Zeiger auf Variablen zu 
mischen. Diese beiden Zeigerarten könnten nämlich unterschiedlich viel 
Speicher brauchen. Allerdings nur bei nicht-POSIX-Systemen.

von Konrad S. (maybee)


Lesenswert?

WiesentM schrieb:
> Würde dieser Code funktionieren? Der Compiler gibt mir eine Warnung
> wegen des übergebenen Typs aus. Aber der Typ ist ja jeweils ein Pointer.

Abgesehen von dem Copy-Paste-Fehler bei der Definition von 
test_2_func(), der einen Error zur Folge hat, würde das schon 
funktionieren.

> Ist es überhaupt möglich ein Array aus Funktionszeigern zu erstellen,
> wobei die Funktionen andere Übergabetypen haben?

Solange die Größe der Array-Elemente groß genug ist, kannst du durch 
entsprechende Casts so ziemlich alles reinprügeln, auch - anders als 
Sven P. schreibt - Zeiger auf Daten und auch Nicht-Zeiger (also z.B. 
Integer). Du musst nur sehr genau wissen was du tust (und ggf. anderen 
antust).

> Die Anzahl der
> Übergabeparameter ist allerdings immer gleich. Soll immer ein Zeiger
> sein, aber eben jeweil ein anderer Typ.

Dazu nimmst man gerne void*:
1
int f1( void *dings )
2
{
3
  sowieso_t *dasda = (sowieso_t *)dings;
4
  ...
5
}
6
...
7
sowieso_t x;
8
f1( &x );

von Rolf Magnus (Gast)


Lesenswert?

Konrad S. schrieb:
> Solange die Größe der Array-Elemente groß genug ist, kannst du durch
> entsprechende Casts so ziemlich alles reinprügeln, auch - anders als
> Sven P. schreibt - Zeiger auf Daten und auch Nicht-Zeiger (also z.B.
> Integer).

Nein, nicht bei einem konformen Compiler. Objekt- und Funktionszeiger 
sind nicht zuweisungskompatibel, auch nicht mit einem Cast. Die meisten 
Compiler lassen es trotzdem zu.

von Sven P. (Gast)


Lesenswert?

Rolf Magnus schrieb:
> Die meisten
> Compiler lassen es trotzdem zu.

Eine POSIX-konforme Umgebung muss es sogar zulassen. Das erwähnte ich 
oben - POSIX garantiert, dass beide Zeigerarten gleichgroß und 
zuweisungskompatibel sind. Diese Festlegung wurde irgendwann mal nötig, 
als die dynamische Linkerei kam, so von wegen dlsym() und so.

von Rolf Magnus (Gast)


Lesenswert?

Sven P. schrieb:
> Rolf Magnus schrieb:
>> Die meisten Compiler lassen es trotzdem zu.
>
> Eine POSIX-konforme Umgebung muss es sogar zulassen.

Ja, obwohl es damit eben im Widerspruch zu ISO C steht.

> Diese Festlegung wurde irgendwann mal nötig, als die dynamische Linkerei
> kam, so von wegen dlsym() und so.

Naja, nötig würde ich nicht unbedingt sagen. Funktionszeiger 
untereinander sind ja durchaus castbar, also hätte man auch eine 
Funktion schreiben können, die einen void(*)(void) zurückgibt, und der 
kann dann bequem in den Zielfunktionszeiger gecastet werden. Man hätte 
halt nur nicht mehr eine einzelne Funktion für Funktions- und 
Objektzeiger gehabt, sondern eben zwei.
Und wie ich gerade auf http://en.wikipedia.org/wiki/Dynamic_loading 
lese, hätte das eigentlich auch mal so werden sollen:


The fact remains that any conversion between function and object 
pointers has to be regarded as an (inherently non-portable) 
implementation extension, and that no "correct" way for a direct 
conversion exists, since in this regard the POSIX and ISO standards 
contradict each other.
Because of this problem, the POSIX documentation on dlsym() (issue 6) 
stated that "a future version may either add a new function to return 
function pointers, or the current interface may be deprecated in favor 
of two new functions: one that returns data pointers and the other that 
returns function pointers".[7] However, the most current version of the 
standard (issue 7, 2008) simply states that function pointers have to be 
convertible to void* for POSIX compliance,[8] leaving compiler makers to 
choose which standard they adhere to.

von Sven P. (Gast)


Lesenswert?

So isses.

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
Noch kein Account? Hier anmelden.