😎

nativeintとnativeptr<'T>とvoidptr

2024/05/01に公開

F#でポインターを扱う際によく登場するnativeintnativeptr<'T>voidptrについてまとめます。

各型について

nativeint

nativeintは実のところ整数型です。内部的にはSystem.IntPtr構造体へのエイリアスになっていますが、それだけではありません。そもそも.NETにおいて整数型には四則演算を行う演算子が定義されておらず、各言語がそれぞれに実装を用意しているだけです。そのため、C#言語においてIntPtr型は整数型と見なされておらず四則演算できません。しかしF#は違います。IntPtrおよびnativeintを整数型として扱い、四則演算を提供しています。
Marshal.Copyメソッドのように多くのクラスライブラリはIntPtrを使います。

nativeptr<'T>

C#言語におけるポインター型です。型としてはあまり登場しませんが、それでも例えばString(char* value)のように引数に現れています。

voidptr

nativeptr<Void>を特別扱いしたポインター型です。ReadOnlySpan<'T>(Void*, Int32)コンストラクターのように最近よく登場するようになった気がします。

相互変換

クラスライブラリを呼び出す際、要求されるポインター型に変換する必要があります。相互変換方法を把握しておく必要があります。

nativeint から nativeptr<'T>

NativePtr.ofNativeIntを使います。

nativeptr<'T> から nativeint

NativePtr.toNativeIntを使います。

voidptr から nativeptr<'T>

NativePtr.ofVoidPtrを使います。

nativeptr<'T> から voidptr

NativePtr.toVoidPtrを使います。

nativeint から voidptr

直接は変換できません。一旦nativeptr<'T>を経由させる必要があります。その際、'Tが決定できませんし、既定のobjでは困りますので、明示的にnativeptr<byte>などを経由させる必要があります。

voidptr から nativeint

直接は変換できません。一旦nativeptr<'T>を経由させる必要があります。その際、'Tが決定できませんし、既定のobjでは困りますので、明示的にnativeptr<byte>などを経由させる必要があります。

相互変換その2

少しでも楽できないか考えました。

nativeint から voidptr

nativeintのエイリアス元であるIntPtrにはToPointer()メソッドがあり、これが使えます。

voidptr から nativeint

nativeintのエイリアス元であるIntPtrにはIntPtr(Void*)コンストラクターがあり、これが使えます。

Discussion