在F#中,有NativePtr模块,但它的添加/获取/设置功能似乎仅支持32位偏移量,就像System.IntPtr一样。
有没有一种方法可以在F#中向 native 指针(nativeptr )添加64位偏移量?当然,我可以将所有地址都转换为64位整数,执行常规的整数运算,然后将结果再次转换为nativeptr ,但这会花费额外的add和imul指令。我真的希望AGU执行地址计算。
例如,在C#中使用不安全,您可以执行以下操作
void* ptr = Marshal.AllocHGlobal(...).ToPointer();
int64 offset = ...;
T* newAddr = (T*)ptr + offset; // T has to be an unmanaged type
嗯,实际上您不能,因为类型参数没有“非托管”约束,但是至少您可以以非泛型方式进行通用指针算术。
在F#中,我们最终得到了不受管理的约束。但是我该怎么做指针算术呢?
最佳答案
我不是该领域的专家,但是我研究了NativePtr
模块的F#实现,并且我认为将nativeptr<'a>
转换为nativeint
以及将其转换回来并没有相关的性能开销。
该实现使用内联IL,并且内联IL代码不包含任何代码-只是为了使F#编译器认为堆栈上的值具有不同的类型:
let inline ofNativeInt (x:nativeint) = (# "" x : nativeptr<_> #)
let inline toNativeInt (x:nativeptr<_>) = (# "" x : nativeint #)
实际上,
NativePtr.add
方法也使用这两种方法-将指针转换为nativeint
,然后添加32位整数(乘以'a
类型的大小)。因此,以下功能应该可以:
let inline addNativeInt (x:nativeptr<'a>) (n:nativeint) : nativeptr<'a> =
(NativePtr.toNativeInt x) + n |> NativePtr.ofNativeInt
代码中使用的所有函数都应内联,因此您最终只会获得一条添加指令(尽管我尚未对此进行验证)。您甚至不必担心在代码中多次使用该功能(您可以一直使用
nativeptr<'a>
并使用此功能进行添加)。但是,也可以选择对数据进行分区-据我所知,使用F#来处理某些大型(> 2GB)数据集的MSR团队正是使用这种方法-他们将数据划分为2GB的块(存储在数组中) 。
关于.net - 将64位偏移量添加到指针,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/2705284/