[C++ Gelöst ] Typecasting Pointer-To-Function und Pointer-To

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Antworten
Tejio
Establishment
Beiträge: 107
Registriert: 11.11.2010, 11:33

[C++ Gelöst ] Typecasting Pointer-To-Function und Pointer-To

Beitrag von Tejio »

Hallo alle zusammen,

kennt ihr eine Möglichkeit, wie man einen void-Pointer zu einem Funktionspointer castet, ohne dass eine Warnung vom Typ "ISO C++ forbids casting between pointer-to-function and pointer-to-object" angezeigt wird?
Im Moment bastle ich an einer kleinen Anwendung zum dynamischen Laden von dynamischen Objekten und hatte mir das Ziel gesetzt, mit meinem GCC-Compiler so gut wie möglich "standardisiert" zu programmieren.

Bisher typecaste ich so

Code: Alles auswählen

template<typename FunctionType>
class Plugin
{
  public:
    typedef Plugin<FunctionType> TypedPlugin;
    static Plugin* at(const std::string& pathToPlugin)
    {
      TypedPlugin* plugin = new TypedPlugin(pathToPlugin);
      return plugin;
    }

    FunctionType extract(const std::string& symbolName)
    {
      void* handle = sobj->getSymbol(symbolName);
      return reinterpret_cast<FunctionType>(handle);
    }

  private:
    /** Lädt ein dynamisches Objekt und gibt einen void-Pointer zurück. */
    SharedObject* sobj;
    Plugin(const std::string& pathToPlugin)
      : sobj(SharedObject::load(pathToPlugin))
    {}
};
Ich hoffe, ihr könnt mir dabei ein wenig helfen, es würde mich riesig freuen =)
Schönen Abend schon mal ;)



PS: Ist bei euch auch so schönes wetter?
Zuletzt geändert von Tejio am 29.07.2011, 14:55, insgesamt 1-mal geändert.
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: [C++] Typecasting Pointer-To-Function und Pointer-To-Obj

Beitrag von CodingCat »

Wie die Fehlermeldung sagt, ist void* kein zulässiger Typ für Funktionszeiger. Funktionszeiger müssen immer Funktionszeiger bleiben, entsprechend kannst du dir am ehesten mit einem eigenen "beliebigen" Funktionszeigertyp behelfen. Dabei kannst du dich z.B. an der WinAPI orientieren, welche bei unbekannter Funktionssignatur stets Funktionszeiger vom Typ typedef int (voidfunc)(); liefert, welche anschließend zu Zeigern der richtigen Signatur gecastet werden.

Damit brichst du allerdings immer noch die Strict-Aliasing-Rule, wenn du ganz korrekt sein willst, und da kommst du leider auch nur sehr schwer raus. Eine Alternative zu reinterpret_cast wäre eine union { voidfunc *vptr; actualfunc *aptr; }, aber selbst das bricht streng genommen die SAR. Ich bin mir nicht mal sicher, ob du das überhaupt 100% standardkonform hinbekommen kannst, auf jeden Fall bist du mal die von dir genannte Warnung los.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Jörg
Establishment
Beiträge: 296
Registriert: 03.12.2005, 13:06
Wohnort: Trondheim
Kontaktdaten:

Re: [C++] Typecasting Pointer-To-Function und Pointer-To-Obj

Beitrag von Jörg »

Standardkonform bekommst Du es mit einem memcpy des allgemeinen Fktptrs in einen mit der gewuenschten Signatur an Stelle des "union-casts".
Zusatz: Wenn Du beide Zeiger in ein struct verpackst und diese kopierst.
Tejio
Establishment
Beiträge: 107
Registriert: 11.11.2010, 11:33

Re: [C++] Typecasting Pointer-To-Function und Pointer-To-Obj

Beitrag von Tejio »

Hallo,

danke euch beiden für euren Antworten! Mit Hilfe von CodingCat habe ich schon mal die Warnungen weg. Der Vorschlag von Jörg ist etwas abschreckend für mich, muss ich sagen. Aber was solls, wenn ich dafür etwas standardkonformer werde :D Immerhin gibt es Makros ;P
void* ist halt der Zeiger, den ich von dlsym bekomme (hab vergessen zu erwähnen, ich arbeite unter Linux).
Danke nochmal für eure Hilfe, es hat mir weitergeholfen!!

Gruß, Tejio
Benutzeravatar
Krishty
Establishment
Beiträge: 8268
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++ Gelöst ] Typecasting Pointer-To-Function und Pointe

Beitrag von Krishty »

Um zu erwähnen, warum Jörg näher dran ist: Der Standard schreibt nicht sizeof(void *) == sizeof(FunctionType) vor. Und auch nicht, dass Funktionen und Daten dasselbe sind (es muss ja nicht alles eine Von-Neumann-Architektur sein und es sagt auch niemand, dass Zeiger durch Adressen realisiert sein müssen). Wenn denn z.B. eine Plattform von vornherein nicht mehr als 64 KiB Programmtext in einem dedizierten Befehlsspeicher verwalten kann (rein hypothetisch) könnte der Compiler im fertigen Programm alle Funktionszeiger als 16-Bit-ints realisieren. Ebenso wäre es dort unmöglich, einen Datenzeiger (pointer-to-object) in einen Befehlszeiger (pointer-to-function) zu konvertieren, weil Daten und Funktionen ja grundsätzlich getrennt wären (Harvard-Architektur).

Auf einigen exotischen Plattformen (überwiegend da, wo ein Byte nicht aus acht Bits besteht) sind Zeiger deshalb tatsächlich unterschiedlich groß, und da würde es dann gewaltig krachen, wenn man mit union eine Konvertierung erzwingen wollte oder der Zeiger auf die Funktion nicht von vornherein ein Funktionszeiger wäre.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Tejio
Establishment
Beiträge: 107
Registriert: 11.11.2010, 11:33

Re: [C++ Gelöst ] Typecasting Pointer-To-Function und Pointe

Beitrag von Tejio »

So, meine Version mit Unions:

Code: Alles auswählen

template<typename InputPtr, typename OutputPtr>
union SharedMemory
{
  InputPtr iptr;
  Outputptr optr;
};

typedef SharedMemory<void*, FunctionType> Handle;

void* vptr = sobject->getSymbol("anysymbol");
Handle.iptr = vptr;
FunctionType fptr = Handle.optr;
Die zweite Version mit dem struct will mir nicht ganz gelingen....

Code: Alles auswählen

struct SMemory
{
  void* iptr;
  FunctionType optr;
};

typedef struct SMemory Memory;

void* vptr = sobject->getSymbol("anysymbol");
Memory m;
m.iptr = vptr;
/*             | */
/*             v  an dieser stelle meckert der compiler rum, dass eine konvertierung von FunctionType zu void* nicht erlaubt ist. */
memcpy(m.optr, m.iptr, sizeof(FunctionType));
/* bei dieser variante hätte man die warnung wieder drin....*/
memcpy((void*)m.optr, m.iptr, sizeof(FunctionType));

Eine Sache steht fest: ich muss mich ein wenig mehr mit der Theoretik der Programmierung beschäftigen..mist ;P
Benutzeravatar
Krishty
Establishment
Beiträge: 8268
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++ Gelöst ] Typecasting Pointer-To-Function und Pointe

Beitrag von Krishty »

Nein, das kriegst du nicht standardkonform. Ein Datenzeiger wie void * kann nicht in einen Funktionszeiger umgewandelt werden, Punkt. So lange dlsym() keinen Funktionszeiger zurückgibt ist da nichts zu machen. Der Compiler hat recht mit der Warnung, du kannst aber nichts dran rütteln – also bleib bei reinterpret_cast und schalt die Warnung einfach ab der union, weil die keine Warnung spuckt.

Aber verschieb den Cast zu getSymbol(), damit das bereits einen Funktionszeiger zurückgibt. (Ist schon richtig so; dlym() kann ja auch Objekte zurückgeben.) Ich weiß gerade auch ehrlich gesagt nicht, ob man bei Funktionszeigern tatsächlich Aliasing Rules befürchten müssen sollte … das sind schließlich statische Daten …

P.S.: Das Problem ist auch schon bekannt.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Jörg
Establishment
Beiträge: 296
Registriert: 03.12.2005, 13:06
Wohnort: Trondheim
Kontaktdaten:

Re: [C++ Gelöst ] Typecasting Pointer-To-Function und Pointe

Beitrag von Jörg »

Oh,da habe ich mich wohl wieder zu kurz gefasst...
Einfach den Funktionszeiger in einer Struct wrappen. Diese kann man kopieren.

Bsp:

typedef int *F1(void);
typedef float *F2(int);

typedef struct s1 { F1 f1; } s1;
typedef struct s2 { F2 f2; } s2;
typedef struct sv { void* p; } sv;

Nun kann man ein einfaches memcpy von Variablen aller 3 typen durchfuehren ( gegeben dass die Typen wirklich die gleiche Groesse haben ).
Das Verwenden einer union ist kritisch, da dort nur das letzte beschriebene Element "gueltig" gelesen werden kann. <= Nachtrag: Ab C99 moeglich.
Benutzeravatar
Krishty
Establishment
Beiträge: 8268
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++ Gelöst ] Typecasting Pointer-To-Function und Pointe

Beitrag von Krishty »

Hier gehe ich nicht konform. Funktionszeiger (bzw. die umgebenden structs) untereinander per memcpy() zu kopieren sieht für mich okay aus; auch, wenn sich die Funktionstypen unterscheiden. Aber void * in einen Funktionszeiger zu kopieren kann nicht richtig sein. Du sagst ja selber: Erstmal müssen die Zeiger dieselbe Größe haben. Darüberhinaus müssen sie aber auch dieselbe Funktionsweise haben. Über beides kannst du durch den Standard keine Annahmen treffen.

Weiterhin: ISO C++ forbids casting between pointer-to-function and pointer-to-object. Für mich klingt das exakt so, als sei aus guten Gründen verboten worden, Daten und Text durcheinanderzuschmeißen. Wir sprechen hier nicht über die Konvertierung vom Zeiger auf einen Typ zu einem Zeiger auf einen anderen Typ, sondern von der Konvertierung zweier unterschiedlicher Arten von Zeigern untereinander. Das ist imo genau so sinnlos wie die Konvertierung eines Pointer-to-member zu einem Pointer-to-data. Siehe auch
Can I convert a pointer-to-member-function to a void*? — No!
Can I convert a pointer-to-function to a void*? — No!
Please do not email me if the above seems to work on your particular version of your particular compiler on your particular operating system. I don't care. It's illegal, period.“

Zusammengefasst: Die ganze Chose ist per Definition nicht standardkonform zu kriegen, weil die bei der POSIX-Fassung einen Fehler gemacht haben und die Funktion fälschlicherweise einen Datenzeiger zurückgibt. Da ändert auch memcpy() nichts.

Darüber hinaus bleibe ich, was Aliasing betrifft, weiterhin kritisch. Imho greifen bei Funktionszeigern keine Strict Aliasing Rules, weil es bei Funktionszeigern kein Aliasing gibt, weil Funktionen keine Lvalues sind. Du kannst keinen Funktionszeiger benutzen um eine Funktion zu verändern. Du kannst sie ausschließlich aufrufen (ich lasse mich aber gern eines besseren belehren.) Darum muss auch niemand annehmen, dass sich der Zielinhalt eines anderen Funktionszeigers irgendwo ändert – ändern ist von sich aus unmöglich.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Jörg
Establishment
Beiträge: 296
Registriert: 03.12.2005, 13:06
Wohnort: Trondheim
Kontaktdaten:

Re: [C++ Gelöst ] Typecasting Pointer-To-Function und Pointe

Beitrag von Jörg »

Pointer-To-Member-Function? Da stand gcc und nicht g++, lass uns nicht abschweifen ;)

Ich wuerde die beiden Moeglichkeiten als standardkonform, aber dennoch platformabhaengig (was C nun mal ist) bezeichnen. Auf manchen Platformen mag es nicht funktionieren (man denke nur an 'tiny, small, medium, huge und large' bzw. deren Zeiger-Groessen von TurboC), aber diese bieten dann wohl auch kein dlsym mit einem void* return typ zur allgemeinen Verwendung an, so dass man folglich auf diese Kruecke nicht angewiesen ist. Es sollte bei beiden Lösungen kein unterschiedliches Programverhalten in unterschiedlichen Compilern erzeugt werden, solange void* und void (*)() auf bitebene identisch sind.
Benutzeravatar
Krishty
Establishment
Beiträge: 8268
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++ Gelöst ] Typecasting Pointer-To-Function und Pointe

Beitrag von Krishty »

Nagut; natürlich kann er zwei Wrapper (je einen für Daten und Funktionen) von dlsym() in eine C-Quelldatei packen und die dann in sein C++-Programm linken. Dann musst du das aber auch schreiben.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Antworten