【发布时间】:2021-03-12 13:27:04
【问题描述】:
我需要与一些低级 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 包含数组y 和yDot 的长度。外部库将提供指向这些数组的第一个元素的指针。
我可以轻松地创建一个供该库使用的 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 的调用都无法编译。对于上面的代码,它在x 和dx 处失败并显示以下消息:
[FS0001] This expression was expected to have type
'nativeptr<float>'
but here has type
'double []'
我可以将neq 和t 声明为可变,然后调用互操作,如:interop.Invoke(&neq, &t, ...。这没什么区别。但是,使用例如&dx.[0] 产生相同的编译器错误。
我需要将指向数组x 和dx 的第一个元素的指针传递给互操作函数。不幸的是,在 F# 中搜索如何将数组转换为 nativeptr 并没有产生任何有用的结果。
谢谢。
【问题讨论】:
-
如果您可以提供编译器错误消息和确切位置,可能更容易判断问题所在。我在想也许
&dx.[0],但我当然可以。 -
n和t不应该是可变的吗?neq实际上是n吗? -neq未在您的测试中定义。如果是可变的,那么它们应该被&n和&t引用? -
我更新了问题以显示编译器错误消息及其发生位置,我还评论了使用可变
t和neq(之前被错误地称为n)。 -
(再看一遍也许这些应该是参考单元格)。无论如何,如果您需要
nativeptr,您需要let (x : double[]) = Array.zeroCreate n let (dx : double[]) = Array.zeroCreate n let tx = NativePtr.ofNativeInt<double> x let tdx = NativePtr.ofNativeInt<double> dx do interop.Invoke(ref neq, ref t, tx.ToPointer(), tdx.ToPointer())这未经测试,但应该有助于作为解决此问题的指南。