2016-11-18 2 views
6

Existe-t-il un moyen d'accéder aux membres d'une structure NativePtr et leur attribuer une valeur, un peu comme vous le pouvez en C# dans l'exemple ci-dessous?F # accesseur de membre de pointeur

(MSDN)

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

Actuellement, je fais usage de NativePtr.write, mais je ne suis pas sûr que ce soit la meilleure/solution correcte.

Merci.

+1

Pour clarifier - vous avez un 'NativePtr ' et vous voulez définir les éléments nommés de cette 'struct'? Avez-vous un exemple de la façon dont vous utilisez actuellement 'NativePtr.write' pour réaliser ceci en F #? –

+2

Oui c'est correct. J'ai fait une fonction qui prend la valeur que je souhaite mettre à jour, le NativePtr et la structure déréférencée de ce pointeur: 'NativePtr.write ptr p'. Avant d'appeler 'NativePtr.write', j'ai mis à jour un membre dans la structure' p'. –

Répondre

4

La façon dont vous avez décrit est la manière la plus claire de le faire, en supposant que vous devez traiter les struct s de cette manière. Par souci de l'exhaustivité, voici cette méthode (avec les détails de mise en œuvre de l'emballage omis):

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 

Cependant, parce que vous devez connaître les compensations exactes de chacun des éléments, vous pouvez également utiliser ces informations pour écrire directement à ce domaine. F # ne fournit pas un moyen de le faire en utilisant des identifiants nommés, et sa frappe stricte du type nativeptr<'T> signifie que vous ne pouvez pas simplement convertir le type de pointeur approprié. La fonction NativePtr.set offset ptr ajoute sizeof<'T> * offset, ce qui est également inutile dans ce cas.

Supposons que le type myStructure possède l'attribut Packed, pour plus de simplicité. Les décalages sont alors 0 pour a et 4 pour b. Jeter toute la prudence au vent, et abandonner complètement le domaine de la mémoire gérée, nous pourrait faire:

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

ou même:

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

Je laisse une question ouverte à Quelle est la meilleure façon de traiter ces situations, si elles doivent être traitées du tout. Je suis enclin à aller avec la première méthode, la plus claire au détriment de l'utilisation de la mémoire supplémentaire. La dernière méthode de décalage arbitraire doit être évitée à tout prix - si vous devez ajouter des compensations brutes, il est beaucoup mieux de les enrouler dans une fonction plus facilement vérifiable comme la seconde méthode, donc l'appelant n'a pas besoin de calculer le décalage lui-même.

+0

Bonne réponse, merci Jake. –