Frage zu Funktionspointern

Gast #2915163
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
Gast #2915181
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.
#2915222
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 );
Gast #2915302
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.
Gast #2915314
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.
Gast #2915337
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren