F# 是否具有 & 和指针取消引用 * 函数的地址?
Does F# have address-of & and pointer dereference * functions?
在 C# 中,我写
unsafe void Main() {
float f = 3.14f;
int i = *(int*)&f;
}
是否可以将此代码转换为 F#?
我的理解是指针由 nativeptr<'a>
类型表示,但我终其一生都找不到地址引用 &
和指针解引用 [=13= 的等价物] 运营商。我怀疑 NativePtr.get
可能是后者,但是its implementation逃避了我,因为我不太了解IL。
我知道 BitConverter
和 Marshal
,但我正在寻找一种无需复制内存即可实现位重整的方法。
NativePtr.get
和 set
函数在偏移量处读写。如果您需要逐字节读取,请使用它。如果您需要在零偏移处读取,可以使用 read
和 write
代替,它们的性能会稍微好一些。
获取 "raw" 地址(相对于 byref<_>
引用)的运算符称为 &&
(see definition)。
但是这里有一些技巧,比如:你需要标记变量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 博士警告我们的那种过早优化。
在 C# 中,我写
unsafe void Main() {
float f = 3.14f;
int i = *(int*)&f;
}
是否可以将此代码转换为 F#?
我的理解是指针由 nativeptr<'a>
类型表示,但我终其一生都找不到地址引用 &
和指针解引用 [=13= 的等价物] 运营商。我怀疑 NativePtr.get
可能是后者,但是its implementation逃避了我,因为我不太了解IL。
我知道 BitConverter
和 Marshal
,但我正在寻找一种无需复制内存即可实现位重整的方法。
NativePtr.get
和 set
函数在偏移量处读写。如果您需要逐字节读取,请使用它。如果您需要在零偏移处读取,可以使用 read
和 write
代替,它们的性能会稍微好一些。
获取 "raw" 地址(相对于 byref<_>
引用)的运算符称为 &&
(see definition)。
但是这里有一些技巧,比如:你需要标记变量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 博士警告我们的那种过早优化。