F# - 如何将数组转换为 nativeptr<double>

标签 f# interop

我需要与一些低级 C/FORTAN 库进行互操作。该库要求我提供一个回调函数,该函数在 C# 中具有以下签名:

public static class Interop
{
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public unsafe delegate void F(
        ref int neq,
        ref double t,
        double* y,
        double* yDot);
}

变量neq包含数组yyDot的长度。外部库将提供指向这些数组的第一个元素的指针。

我可以轻松创建一个供该库使用的 F# 互操作,例如:

let private f (neq : byref<int>, t : byref<double>, x : nativeptr<double>, dx : nativeptr<double>) : unit =

    for i in 0 .. (neq - 1) do
        NativePtr.set dx i (NativePtr.get x i)


let createInterop() = Interop.F(fun n t y dy -> f(&n, &t, y, dy))

它有效,我可以看到该函数正在被调用并执行某些操作。

现在,我想编写一个测试来确保我创建的互操作正常工作。

let interopTest() =
    let neq = 10
    let t = 0.0
    let (x : double[]) = Array.zeroCreate n
    let (dx : double[]) = Array.zeroCreate n
    let interop = createInterop()

    // Call the interop. ! DOES NOT COMPILE !
    do interop.Invoke(ref neq, ref t, x, dx)

    // Verify the results.

无论尝试什么,对 interop.Invoke 的调用都无法编译。对于上面的代码,它在 xdx 处失败,并显示消息:

[FS0001] This expression was expected to have type
    'nativeptr<float>'    
but here has type
    'double []'

我可以将 neqt 声明为可变的,然后调用互操作,如下所示:interop.Invoke(&neq, &t, ... .这没有什么区别。但是,使用例如 &dx.[0] 会产生相同的编译器错误。

我需要将指向数组 xdx 的第一个元素的指针传递给互操作函数。不幸的是,搜索如何在 F# 中将数组转换为 nativeptr 没有产生任何有用的结果。

谢谢。

最佳答案

这是“如何在 F# 中将数组转换为 nativeptr”的方法:

open Microsoft.FSharp.NativeInterop  
    
let private f (neq : byref<int>, t : byref<double>, x : nativeptr<double>, dx : nativeptr<double>) : unit =

    for i in 0 .. (neq - 1) do
        NativePtr.set dx i (NativePtr.get x i)

let createInterop() = fun n t y dy -> f(&n, &t, y, dy))

let interopTest() =
    let n = 10
    let t = 0.0
    let (x : double[]) = Array.zeroCreate n
    let (dx : double[]) = Array.zeroCreate n

    let tx = NativePtr.ofNativeInt<double> x     
    let tdx = NativePtr.ofNativeInt<double> dx     
   
    let interop = createInterop()

    // Call the interop. Does compile but does not call your c# interop
    // but does create the correct nativeptr(s)
    interop n  t tx tdx

    // Verify the results.

更新:

显然这对 OP 不起作用,但 txtdx 都在 VS Code 中产生相同的正确类型,至少对我来说是这样。不管怎样,这展示了做同样事情的另一种有趣的方式,也许其他人可能会发现一种方法有效,而另一种则无效?

let interopTest() =
    let n = 10
    let t = 0.0
    let (x : double[]) = Array.zeroCreate n
    let (dx : double[]) = Array.zeroCreate n

    let tx = fixed &x.[0]    // val tx: nativeptr<double>
    let tdx = fixed &dx.[0]  // val tdx: nativeptr<double>

      
    let interop = createInterop()

    // Call the interop.
    do interop.Invoke(ref n, ref t, tx, tdx)

    // Verify the results.

关于F# - 如何将数组转换为 nativeptr<double>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66600792/

相关文章:

c# - C# 代码中的模式匹配 F# 类型

c# - 如何将非托管对话框设置为 WinForm 窗体的所有者?

f# - 将 TestCase 与 fsunit 一起使用

f# - 如何使用 F# WMI 类型提供程序连续获取计数器值

.net - 如何强制 app.config 成为 exe.config

c++ - QML 中的类型化数组? QByteArray 到 JS Uint8Array 来回互操作

c# - PresentationSource.FromVisual(this) 在 WPF 中返回空值

F# - splat/解包参数列表

f# - 使用 F# Struct 和 Explicit LayoutKind 创建标记联合

winapi - Rust WINAPI输出HMODULE值