F#是否具有地址和&指针解除引用*功能?

kkm*_*kkm 4 f# pointers unsafe inline byref

在C#中,我写道

unsafe void Main() {
  float f = 3.14f;
  int i = *(int*)&f;
}
Run Code Online (Sandbox Code Playgroud)

是否可以将此代码转换为F#?

我的理解是指针是由nativeptr<'a>类型表示的,但我对于我的生活我找不到相当于地址引用&和指针解引用的*运算符.我怀疑 NativePtr.get可能是后者,但它的实现逃脱了我,因为我不太了解IL.

我知道BitConverterMarshal,但我正在寻找一种方法来实现位修改而不复制内存.

Fyo*_*kin 7

NativePtr.getset功能读取和偏移写.如果需要逐字节读取,则使用它.如果你需要在零偏移处读取,你可以使用它read,write相反,它们会稍微提高性能.

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
Run Code Online (Sandbox Code Playgroud)

或者更紧凑的版本:

open FSharp.NativeInterop

let Main() =
  let mutable x = 3.1415
  &&x |> NativePtr.toNativeInt |> NativePtr.ofNativeInt |> NativePtr.read<int>
Run Code Online (Sandbox Code Playgroud)

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

// 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
  ()
Run Code Online (Sandbox Code Playgroud)

说完以上所有内容后,我完全赞同John Palmer和GuyCoder:如果可能的话,请不要这样做.这看起来就像Knuth博士警告我们的那种过早优化.

  • 请注意,C#的`float`在F#中称为`float32`. (3认同)