Array fester Größe vom Typ Struct



  • Hallo,

    für den Zugriff auf Elemente einer in C++ erstellten Bibliothek möchte ich in C# die dort verwendeten Structs nachbilden. In C++ habe ich:

    typedef struct TNode {
    */Inhalt*/
    }TNode
    
    typedef struct TEdge
        struct TNode* ppNode [2]; /*Problem*/
        /*Weiterer Inhalt*/
    }TEdge
    

    Allerdings darf ich in C# kein Array fester Größe in einem Struct definieren bzw. ich weiß nicht wie. Fixed funktioniert nur bei wenigen Basistypen.

    In erster Linie möchte ich von C# aus auf die Daten der DLL zugreifen. Dort liegen ganze Arrays mit z.B. TEdge. C# muss also die exakte Länge eines solchen Structs kennen.

    In C# habe ich es wie folgt versucht:

    [StructLayout (LayoutKind.Sequential)]
    public struct TNode
    {
    /*Inhalt*/
    }
    
    [StructLayout (LayoutKind.Sequential)]
    public struct TEdge
    {
        public fixed TNode* ppNode [2] /*Fehler beim kompilieren*/
    
    /*weitere Einträge*/
    }
    

    Vielen Dank für alle Anregungen.

    Gruß,
    CJens



  • Musst du wohl ppNode1, PpNode2 etc schreiben.



  • Aber dann passt die Struktur doch nicht mehr zu der DLL aus C++!?!
    Woher weiß C# dann, dass ppNode1 = ppNode[0] etc.?

    Ich möchte später in C# z.B. über pEdge[xyz]->ppNode[1].Index auf die Daten zugreifen, indem ich mir von der DLL den Zeiger auf das TEdge-Array übergeben lasse. Ohne diesen Eintrag public fixed TNode* ppNode [2] funktioniert das auch.

    Wieso geht das in C# nicht? Übrigens ist fixed auch in Kombination mit IntPtr gültig. Wieso? Jeder Zeiger hat 4byte, die Größe ist also bekannt.



  • Wenn das Speicherlayout (variablennamen sowie typen etc sind in einem nativen Programm übrigens _nicht_ mehr vorhanden) der struct in der dll mit der von c# übereinstimmt passt es doch.



  • Ok, werde das mal versuchen, auch wenn es mir nicht gefällt.Später habe ich in Strukturen auch größere Arrays mit Nichtbasistypen.

    Kann man das evtl. durch Marshalling hin bekommen z.B. Marshal.PrtToStructure()? Oder kann man grundsatzlich sagen, dass in C# nur Arrays der Basistypen mit fester Größe in Structs definiert werden können?



  • Anbei meine Structs in voll Länge:

    typedef struct TPoint{
      double x [3];
    }TPoint;
    
    typedef struct TNode {
      struct TPoint P;
    
      struct TCell** EP;
      unsigned int nEP;
      double Value;
    }TNode;
    
    typedef struct TFace {
      struct TPoint P;
      struct TNode** ppNode;
      unsigned int nNode;
      struct TCell* E [2];
    }TFace;
    
    typedef struct TCell {
      struct TPoint P;
      struct TFace** ppFace;
      unsigned int nFace;
    }TCell;
    

    In der C-DLL wird über eine interne Funktion Speicher angelegt und ein Gitter eingeladen. Knoten (TNode) spannen Flächen (TFace) auf und mehrere verbundene Flächen bilden eine Zelle (TCell). Dabei habe ich von den Knoten aus Zugriff auf alle Zellen, die den Knoten hinhalten über EP - ein Feld mir den Zeigen auf alle dieser Zellen. Bei TFace habe ich über E Zugriff auf die beiden Zellen, welche diese Fläche beinhalten - das können maximal zwei sein. Ist E [1]=NULL ist es eine Außenfläche.

    Und ich schaffe es in C# nicht, ein eindimensionales Array eines Zeigers auf einen benutzerdefinierten Typ der bekannten Länge 2 in einer Struktur zu definieren.
    Den Zugriff über Zeiger1 und Zeiger2 finde ich etwas schmutzig denn wer garantiert, dass diese Größe an der selben Stelle in der Struktur abgelegt werden?

    Geht das nicht sauberer? Ist ohnehin recht schmutzig unsafe zu arbeiten, aber ich möchte diese Daten nur einmal im Speicher haben.



  • Hallo,

    lade dir mal den PInvoke Interop Assistant herunter und schau was der als Ausgabe erzeugt (2. Tab: Generate Code [oder so ähnlich]).

    Schau dir auch mal das MarshalAsAttribute an.
    Unter Marshaling with C# – Chapter 1: Introducing Marshaling ff. gibt es auch einen passenden Artikel dazu.



  • Vieleich wäre es ganz sinvoll hierbei mit swig zu arbeiten.
    swig.org
    Hat bei mir eigentlich immer gut funktioniert, wenn ich einen Call in eine C oder C++ DLL von C# aus machen wollte.


Log in to reply