Pointer auf Funktion? oder?
-
Hallo zusammen
Ich bin neu hier im Forum und freue mich hier mit zu machen.
Ich habe in einem Source Code den ich analysieren muss, folgenden Code gefunden den ich nicht verstehe:
void (*funcp)(void);
(void*)(&funcp) = sosym(fdHandle, symbol)
Was bedeutet das?
Danke für eure Antworten.
Grus
Dino
-
void (*funcp)(void);
Das ist ein Zeiger auf eine Funktion, die void zurück gibt und keine Argumente hat. Dieser Zeiger hat die Bezeichnung funcp. Um so etwas zu entziffern, ist auch folgende Seite gut (nach einer Weile wirst du dich aber dran gewöhnen, dann liest man das ganz flüssig):
http://cdecl.ridiculousfish.com/?q=void+(*funcp)(void)*(void**)(&funcp) = sosym(fdHandle, symbol)
Hier wird die Adresse des Zeigers genommen
(&funcp)
. Diese wird in einen Zeiger auf Zeiger auf void gecastet ((void**)(&funcp)
), das heißt, sie wird benutzt als wäre sie von diesem Typen. Das Ergebnis wird wiederum dereferenziert (das Sternchen vor allem), wodurch man also wieder den Zeiger funcp bekommt, dieses Mal jedoch aufgefasst als Zeiger auf void. Diesem wird etwas zugewiesen.
Dieses Konstrukt ist nicht so schön, das ist Absicht. Denn hier wird ein void-Pointer einem Funktionszeiger zugewiesen. Das geht eigentlich nicht, denn diese Typen sind nicht unbedingt kompatibel. Dieser Hack sagt aber so viel wie "ich bin mir absolut sicher, dass das so in Ordnung ist, ich möchte keine Warnungen oder Fehlermeldungen hören". Wenn man das also macht, sollte man sich wirklich sicher sein, dass das so in Ordnung ist.Jedenfalls ist hier an mindestens einer Stelle ein Designfehler. Entweder solle funcp kein Funktionszeiger sein oder sosym sollte keinen void-Pointer zurück geben. Durch diese Schreibweise kann man die beiden dann aber trotzdem verheiraten, sofern man sich sicher ist, dass auf dem Zielsystem die beiden Typen kompatibel sind.
Faustregel: Mische nicht Daten- und Funktionszeiger!
-
SeppJ schrieb:
Jedenfalls ist hier an mindestens einer Stelle ein Designfehler.
Wie würdest du es denn lösen?
-
Bashar schrieb:
SeppJ schrieb:
Jedenfalls ist hier an mindestens einer Stelle ein Designfehler.
Wie würdest du es denn lösen?
Kommt drauf an, was genau der Fehler ist und wer was programmiert hat.
Szenarien:A:
-sosym ist Gottgegeben
-sosym gibt einen Funktionszeiger zurück, aber als void*
Fehler liegt in der Programmierung von sosym. Der hier gezeigte Hack ist der übliche und passende Workaround
B:
-sosym und funkptr sind beide unter meiner Kontrolle
Mindestens bei einem habe ich Mist gebaut. Daher korrigieren. Wahrscheinlich ist der Rückgabetyp von sosym falsch (wenn es tatsächlich ein Funktionszeiger darstellen soll). Eventuell auch der Typ von funkptr (wenn sosym auf Daten zeigt).
-
SeppJ schrieb:
-sosym und funkptr sind beide unter meiner Kontrolle
Mindestens bei einem habe ich Mist gebaut. Daher korrigieren.
Und wie?
Wahrscheinlich ist der Rückgabetyp von sosym falsch (wenn es tatsächlich ein Funktionszeiger darstellen soll).
Was ist der richtige Typ?
Eventuell auch der Typ von funkptr (wenn sosym auf Daten zeigt).
Das wär ja schwachsinnig, das können wir ausschließen.
-
Bashar schrieb:
SeppJ schrieb:
-sosym und funkptr sind beide unter meiner Kontrolle
Mindestens bei einem habe ich Mist gebaut. Daher korrigieren.
Und wie?
Indem man es ändert?
Wahrscheinlich ist der Rückgabetyp von sosym falsch (wenn es tatsächlich ein Funktionszeiger darstellen soll).
Was ist der richtige Typ?
Offensichtlich doch
void(*)(void)
. Zur allergrößten Not darf man laut Standard sogar davon ausgehen, dass alle Funktionszeigertpyen miteinander kompatibel sind, so dass man nach einer Konvertierung und Rückkonvertierung wieder den gleichen Zeiger erhält. Aber hier kennt man ja schon den korrekten Zeigertyp.Ich bin gerade sehr verwirrt, wieso du diese Frage stellst. Worauf willst du hinaus? Ich habe den Eindruck, hier liegt ein Kommunikationsproblem vor. Wenn ich deine Fragen richtig verstehe, dann sind es Fragen, die du nicht stellen bräuchtest, denn das weißt du alles. Wenn du auf irgendetwas anderes hinaus möchtest, dann sag es, denn ich habe keine Ahnung, worauf du abzielst.
-
SeppJ schrieb:
Bashar schrieb:
Was ist der richtige Typ?
Offensichtlich doch
void(*)(void)
.Was ist denn daran offensichtlich? Du weißt doch gar nicht, wie sosym arbeitet. Aufgrund der Ähnlichkeit zu dlsym (was sich auch im Namen niederschlägt) würde ich ganz stark davon ausgehen, dass sosym Zeiger auf beliebige Funktionstypen zurückliefern kann.
Zur allergrößten Not darf man laut Standard sogar davon ausgehen, dass alle Funktionszeigertpyen miteinander kompatibel sind, so dass man nach einer Konvertierung und Rückkonvertierung wieder den gleichen Zeiger erhält.
Das wäre eine Möglichkeit, vielleicht wäre das noch eine bessere Lösung.
Ich bin gerade sehr verwirrt, wieso du diese Frage stellst. Worauf willst du hinaus? Ich habe den Eindruck, hier liegt ein Kommunikationsproblem vor. Wenn ich deine Fragen richtig verstehe, dann sind es Fragen, die du nicht stellen bräuchtest, denn das weißt du alles.
[/quote]
Ich weiß so viel nicht.
-
Bashar schrieb:
SeppJ schrieb:
Bashar schrieb:
Was ist der richtige Typ?
Offensichtlich doch
void(*)(void)
.Was ist denn daran offensichtlich?
Weil entweder der Typ von funkptr passt oder eben nicht. Wenn das Szenario lautet, dass der Typ von funkptr passt, dann ist der Typ von funkptr der richtige Rückgabetyp. Oder es ist eben das andere Szenario, in dem es irgendein allgemeiner Funktionszeiger ist, da weiß man eben nur, dass es irgendein Funktionszeiger ist.
void(*)(void)
wäre auch da passend (auch wenn alles andere auch funktionieren würde), weil es keine verwirrenden Angaben über die Funktion macht, die ohnehin nicht stimmen (auch wennint (*(*)(double))(float)
funktioniert, würde sich jeder wundern, warum die Signatur ausgerechnet so aussieht). Jedenfalls nichtvoid*
, das ist für allgemeine Daten da.
-
Bashar schrieb:
Aufgrund der Ähnlichkeit zu dlsym (was sich auch im Namen niederschlägt) würde ich ganz stark davon ausgehen, dass sosym Zeiger auf beliebige Funktionstypen zurückliefern kann.
Nicht nur Zeiger auf Funktionen, sondern Adressen beliebiger Symbole. XSI verlangt daher, dass void* einen Funktionszeiger speichern kann.
dlsym - IEEE Std 1003.1-2004 schrieb:
RATIONALE
The ISO C standard does not require that pointers to functions can be cast back and forth to pointers to data. Indeed, the ISO C standard does not require that an object of type void * can hold a pointer to a function. Implementations supporting the XSI extension, however, do require that an object of type void * can hold a pointer to a function. The result of converting a pointer to a function into a pointer to another data type (except void
is still undefined, however. Note that compilers conforming to the ISO C standard are required to generate a warning if a conversion from a void * pointer to a function pointer is attempted as in:
fptr = (int (*)(int))dlsym(handle, "my_function");
Due to the problem noted here, 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.
Klar ist das nicht unbedingt ideal. Ich bezweifle allerdings, dass die im letzten Absatz beschriebene mögliche Änderung in absehbarer Zeit realisiert wird. In der Tat sieht es sogar so aus, als sei der Absatz in neueren Versionen des Standards gestrichen worden.