C# Pointer

  • C#
  • .NET (FX) 4.5–4.8

Es gibt 5 Antworten in diesem Thema. Der letzte Beitrag () ist von exc-jdbi.

    Hallo Community

    Ich arbeite mich ein bisschen in die unsafe-Geschichte ein.
    Soweit finde ich das eine spannende Sache, denn es gibt so
    viel Ähnlichkeiten zu C++.

    Das fixed-Statement verwende ich noch oft
    wenn es erforderlich ist

    C#-Quellcode

    1. ManagedType[] obj = new ManagedStruct[];
    2. fixed (ManagedType* ptr = ManagedStruct)
    3. {
    4. //Von hier aus arbeite ich das durch
    5. //was gewünscht ist.
    6. }


    Soweit alles IO.
    Ich würde diesen Teil gerne ein bisschen erweitern
    und hab mir dazu Methoden gemacht.

    C#-Quellcode

    1. public static unsafe ManagedType* ToPointer<ManagedType>
    2. (int size)
    3. where ManagedType : unmanaged
    4. {
    5. //Nur der Pointer soll übergeben werden
    6. var result = new ManagedType[size] ;
    7. fixed (ManagedType* ptr = result)
    8. return ptr;
    9. }
    10. public static unsafe ManagedType* ToPointer<ManagedType>
    11. (ManagedType[] ManagedStruct)
    12. where ManagedType : unmanaged
    13. {
    14. //Nur der Pointer soll übergeben werden
    15. fixed (ManagedType* ptr = ManagedStruct)
    16. return ptr;
    17. }
    18. public static unsafe ManagedType* ToPointer<ManagedType>
    19. (ManagedType ManagedStruct)
    20. where ManagedType : unmanaged
    21. {
    22. var result = new[] { ManagedStruct };
    23. fixed (ManagedType* ptr = result)
    24. return ptr;
    25. }


    Sind die legitim?

    Wie man erkennen kann wird immer ein Pointer zurückgegeben.
    Müssen die irgendwie speziell behandelt werden?
    Müssen die Pointer irgendwann z.B. zurückgesetzt werden?

    Ich habe jetzt überall gesucht und recherchiert aber
    so richtig bestätigt wurde ich nicht mit den Antworten.

    Eventuell hat jemand noch einen sehr guten Link, wo
    tiefer und vor allem intensiver sich mit diesem Thema
    beschäftigt, als die Seite von Microsoft.

    Danke für die Antworten.

    Freundliche Grüsse

    exc-jdbi

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „exc-jdbi“ ()

    @exc-jdbi C#-Pointer kannst Du behandeln wie C++-Pointer, da muss nix zurückgesetzt werden.
    Um ggf. Fehlzugriffe zu vermeiden, kannst Du unsafe als Block in einer Prozedur einsetzen, dann wie in Deinem Code als Attribut von Prozeduren und auch als Attribut von Klassen.
    Hier ist es sinnvoll, den Scope so klein wie möglich zu machen, dann passt der Compiler auf, dass Du nicht außerhalb davon auf Pointer zugreifst.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    exc-jdbi schrieb:

    Sind die legitim?

    Leider nein. Die CLR schiebt zur Laufzeit den Speicher möglicherweise hin und her. Intern hat diese alle Verweise oder Pointer gespeicher und schiebt diese dann mit. Dein eigener Pointer gehört nicht dazu. Mit dem fixed Statement sagst du der CLR praktisch "Stop! Diesen Speicher jetzt nicht verschieben, da arbeite ich dran". Deswegen ist der Pointer nur innerhalb dieses Statements gültig. Man kann zwar viel mit den Pointern machen, aber nicht komplett frei hantieren. Dazu solltest du dir dann eher nochmal das ref Schlüsselwort anschauen.
    Danke ROF das habe ich bis jetzt auch immer gemacht.

    Nun möchte ich jedoch mehr mit Methoden arbeiten damit ich die Pointer auch rumreichen kann.
    Die jeweiligen "Unsafe-Methoden" werde ich in dem Falle immer so klein wie nötig halten.

    Später wird ich mir eine Dll machen die ich gleichzeitig für C# wie auch VB.NET verwenden möchte.
    Muss ich da mit bestimmten direktiven arbeiten? Abgrenzung VB.NET und C#. Einstiegspunkte?


    Edit: Danke @Bluespide
    Nehmen wie an ich möchte soweit wie möglich mit den Pointers arbeiten schon aus Übungszwecken,
    und daher die "ref" nur verwenden wenn es unbedingt nötig ist.

    Soll ich da eher auf die GcHandle-Pinned-Pointer umsteigen?

    Freundliche Grüsse

    exc-jdbi

    exc-jdbi schrieb:

    Soll ich da eher auf die GcHandle-Pinned-Pointer umsteigen?

    Richtig, hier nochmal der Auszug aus MSDN fixed-Anweisung:
    Die fixed-Anweisung setzt einen Zeiger auf eine verwaltete Variable und „fixiert“ diese Variable während der Ausführung der Anweisung. Zeiger auf verschiebbare verwaltete Variablen sind nur in einem fixed-Kontext nützlich. Ohne den fixed-Kontext könnte die automatische Speicherbereinigung die Variablen auf unvorhersehbare Weise verschieben.


    Und zu GCHandle.AddrOfPinnedObject Methode:
    Durch das Anhebungs eines Objekts wird verhindert, dass das Garbage Collector es im Arbeitsspeicher verschiebt, wodurch die Effizienz des Garbage Collector verringert wird.


    Du kannst damit also dann die Pointer sicher verwenden, machst dir aber in einem echten Anwendungsfall möglicherweise die erhoffte Performancegewinnung durch die Blockade des GC's wieder kaputt. Möglichereweise.
    Hier hab ich noch ein Link dafür.
    stackoverflow.com/a/8095223

    C#-Quellcode

    1. var cnt = 3;
    2. var src = new[] { 0, 1, 2, 3,4, 5 };
    3. var dst = new int[cnt];
    4. unsafe
    5. {
    6. fixed (int* p1 = src, p2 = dst)
    7. FillArray(p1, p2, src.Length, dst.Length, cnt);
    8. //Weiterer Code
    9. }

    C-Quellcode

    1. public static unsafe void FillArray<ManagedType>
    2. (ManagedType* ManagedSrcArray, ManagedType* ManagedDstArray,
    3. int ManagedSrcArraySize, int ManagedDstArraySize, int count)
    4. where ManagedType : unmanaged
    5. {
    6. if (ManagedSrcArraySize - count < 0 ||
    7. ManagedDstArraySize - count < 0)
    8. throw new OverflowException("Size");
    9. for (int i=0 ; i < count; i++)
    10. {
    11. //Zuweisen der Valuwerte Src >> Dest; Anzahl count
    12. *(ManagedDstArray + i) = *(ManagedSrcArray + i);
    13. }
    14. }

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „exc-jdbi“ ()