F# 是否有地址 & 和指针取消引用 * 函数?



在C#中,我编写

unsafe void Main() {
  float f = 3.14f;
  int i = *(int*)&f;
}

有可能把这个代码翻译成F#吗?

我的理解是,指针由nativeptr<'a>类型表示,但我一生都找不到地址引用&和指针取消引用*运算符的等价物。我怀疑NativePtr.get可能是后者,但我无法理解它的实现,因为我对IL的理解不够好。

我知道BitConverterMarshal,但我正在寻找一种在不复制内存的情况下实现位篡改的方法。

NativePtr.getset函数以偏移量进行读取和写入。如果你需要一个字节一个字节地读取,那么就使用它。如果您需要在偏移量为零的情况下读取,可以使用readwrite,它们的性能会稍高一些。

用于获取"原始"地址(与byref<_>引用相反)的运算符称为&&(参见定义)。

但还涉及一些技巧,例如:在获取变量mutable的地址之前,您需要标记它,您不能只存储nativeptr<_>值,您需要将其转换为nativeint,再加上nativeptr<_>值是强类型的,因此您需要通过nativeint在它们之间进行转换,等等。

下面的代码片段将与您的C#代码等效(一步一步,并使用完整的类型注释以提高清晰度):

open FSharp.NativeInterop
let Main() =
  let mutable x: float = 3.1415
  let floatPtr: nativeint = NativePtr.toNativeInt<float> &&x
  let intPtr: nativeptr<int> = floatPtr |> NativePtr.ofNativeInt<int>
  let asInt: int = NativeInterop.NativePtr.read intPtr
  asInt

或者更紧凑的版本:

open FSharp.NativeInterop
let Main() =
  let mutable x = 3.1415
  &&x |> NativePtr.toNativeInt |> NativePtr.ofNativeInt |> NativePtr.read<int>

或者将其打包以供重复使用:

// val inline readAs : x:'a -> 'b when 'a : unmanaged and 'b : unmanaged
let inline readAs (x: 'a) : 'b =
  let mutable x' = x
  &&x' |> NativePtr.toNativeInt |> NativePtr.ofNativeInt |> NativePtr.read<'b>
let Main() =
  let i = readAs 3.1415 : int
  ()

说了这么多,我完全同意John Palmer和GuyCoder的观点:如果可能的话,请不要这样做。这看起来正是Knuth博士警告我们的那种过早的优化。

相关内容

  • 没有找到相关文章

最新更新