2016-11-18 1 views
6

Gibt es eine Möglichkeit, auf die Mitglieder einer NativePtr-Struktur zuzugreifen und ihnen einen Wert zuzuweisen, ähnlich wie in C# im folgenden Beispiel?F # -Zeiger-Accessor

(Von MSDN)

CoOrds* p = &home; p -> x = 25;

Derzeit Verwendung von NativePtr.write Ich mache, aber ich bin nicht sicher, ob dies die beste/richtige Lösung ist.

Danke.

+1

Um zu verdeutlichen - Sie haben eine 'NativePtr ' und Sie möchten die benannten Elemente dieser 'struct' setzen? Haben Sie ein Beispiel dafür, wie Sie 'NativePtr.write' verwenden, um dies in F # zu erreichen? –

+2

Ja, das ist richtig. Ich habe eine Funktion gemacht, die den Wert, den ich aktualisieren möchte, den NativePtr und die dereferenzierte Struktur von diesem Zeiger nimmt: 'NativePtr.write ptr p'. Vor dem Aufruf von 'NativePtr.write' habe ich ein Mitglied innerhalb der' p' Struktur aktualisiert. –

Antwort

4

Die Art und Weise, wie Sie beschrieben haben, ist die klarste Art und Weise dies zu tun, vorausgesetzt, dass Sie auf diese Weise mit der struct s umgehen müssen. Der Vollständigkeit halber ist hier, dass Verfahren (mit den Implementierungsdetails der Verpackung weggelassen):

open FSharp.NativeInterop 

[<StructLayout(...)>] 
type myStructure = 
    struct 
     val mutable a : int 
     val mutable b : byte 
    end 

let changeA pointer newA = 
    let mutable structure = NativePtr.read pointer 
    structure.a <- newA 
    NativePtr.write pointer structure 

Da Sie jedoch die genauen Offsets jedes der Elemente wissen müssen, können Sie auch diese Informationen benutzen, direkt zu schreiben zu diesem Feld. F # bietet keine Möglichkeit, dies unter Verwendung benannter Bezeichner zu tun, und seine genaue Eingabe des Typs nativeptr<'T> bedeutet, dass Sie nicht einfach auf den entsprechenden Zeigertyp umwandeln können. Die NativePtr.set offset ptr Funktion fügt sizeof<'T> * offset hinzu, so dass dies auch in diesem Fall nicht verwendet wird.

Nehmen wir an, der Typ hat zur Vereinfachung das Attribut Packed. Die Offsets sind dann 0 für a und 4 für b. Werfen Sie alle Vorsicht in den Wind und vollständig in das Reich der verwalteten Speicher zu verlassen, wir konnte tun:

let changeB pointer newB = 
    let bPtr = 
     NativePtr.toNativeInt pointer 
     |> (+) 4n 
     |> NativePtr.ofNativeInt<byte> 
    NativePtr.write bPtr newB 

oder sogar:

let changeMember pointer offset (value : 'T) = 
    let pointer' = 
     NativePtr.toNativeInt pointer 
     |> (+) (nativeint offset) 
     |> NativePtr.ofNativeInt<'T> 
    NativePtr.write pointer' value 

Ich überlasse es eine offene Frage, was die beste Methode des Umgangs mit diesen Situationen ist, wenn sie überhaupt behandelt werden müssen. Ich neige dazu, mit der ersten, klarsten Methode auf Kosten der zusätzlichen Speicherbenutzung zu gehen. Die letzte, willkürliche Offset-Methode soll um jeden Preis vermieden werden - wenn Sie mit dem Hinzufügen von Raw-Offsets umgehen müssen, ist es viel besser, sie in eine leichter verifizierbare Funktion wie die zweite Methode einzubetten, so dass der Aufrufer den Offset nicht berechnen muss selbst.

+0

Große Antwort, danke Jake. –