我正在尝试通过将open source library, written in C包裹起来并将其暴露给.Net来使用它。我决不是C专家。
到目前为止,我已经设法从F#调用用C编写的演示代码。通过遵循this guide,然后填补空白,我设法做到了这一点。我已经改编了C代码以期望将int传递给它,因此我至少可以将F#的标量值传入C。但是没有返回值。
但是处理数组要复杂得多。
我的C代码是
extern "C"
{
__declspec(dllexport) void DisplayHelloFromDLL(int i)
{
//printf("Hello from DLL !\n");
cout << "You gave me ... an int: " << i << endl;
// Load problem data
c_float P_x[4] = { 4., 1., 1., 2., }; //covariance matrix
c_int P_nnz = 4; //number of non-zero elements in covar
c_int P_i[4] = { 0, 1, 0, 1, }; //row indices?
c_int P_p[3] = { 0, 2, 4}; //?
c_float q[2] = { 1., 1., }; //linear terms
c_float A_x[4] = { 1., 1., 1., 1., }; //constraint coefficients matrix
c_int A_nnz = 4; //number of non zero elements in constraints matrix
c_int A_i[4] = { 0, 1, 0, 2, }; //row indices?
c_int A_p[3] = { 0, 2, 4}; //?
c_float l[3] = { 1., 0., 0., }; //lower bounds
c_float u[3] = { 1., 0.7, 0.7, }; //upper bounds
c_int n = 2; //number of variables (x)
c_int m = 3; //number of constraints
// Problem settings
OSQPSettings *settings = (OSQPSettings *)c_malloc(sizeof(OSQPSettings));
// Structures
OSQPWorkspace *work; // Workspace
OSQPData *data; // OSQPData
// Populate data
data = (OSQPData *)c_malloc(sizeof(OSQPData));
data->n = n;
data->m = m;
data->P = csc_matrix(data->n, data->n, P_nnz, P_x, P_i, P_p);
data->q = q;
data->A = csc_matrix(data->m, data->n, A_nnz, A_x, A_i, A_p);
data->l = l;
data->u = u;
// Define Solver settings as default
osqp_set_default_settings(settings);
// Setup workspace
work = osqp_setup(data, settings);
// Solve Problem
osqp_solve(work);
// Clean workspace
osqp_cleanup(work);
c_free(data->A);
c_free(data->P);
c_free(data);
c_free(settings);
}
}
我的C#代码是
class Program
{
[DllImport("TestLibCpp.dll")]
public static extern void DisplayHelloFromDLL(int i);
static void Main(string[] args)
{
Console.WriteLine("This is F# program");
DisplayHelloFromDLL(52);
}
}
为使此问题的重点保持狭窄:我如何将P_x设置为要从F#传递的参数?
答案 0 :(得分:2)
阅读AlexF的链接并开始工作后,我认为我会在这里为有类似问题的任何人提供答案。 我可能会误解某些概念,但是代码可以正常工作。如果我弄错了任何细节,请告诉我,我将进行编辑。
要注意的概念: 可漂白类型:这些类型在.Net(托管)和C(非托管)中具有相同的内部表示形式。可调度类型由封送拆收器“固定”,这似乎意味着将指针从.Net传递到C,而不是复制值。 Blittable类型的内存位置被锁定,直到返回非托管函数为止。不确定这会如何影响垃圾收集。
输入/输出属性:可填充数组作为输入参数传递。如果要使用它们作为返回值,则必须将它们明确标记为Out。
无论如何,这是有效的代码。
不受管理:
extern "C"
{
__declspec(dllexport) void DisplayHelloFromDLL(c_float* P_x)
{
//printf("Hello from DLL !\n");
//cout << "You gave me ... an int: " << i << endl;
// Load problem data
//c_float P_x[4] = { 4., 1., 1., 2., }; //covariance matrix
c_int P_nnz = 4; //number of non-zero elements in covar
c_int P_i[4] = { 0, 1, 0, 1, }; //row indices?
c_int P_p[3] = { 0, 2, 4}; //?
c_float q[2] = { 1., 1., }; //linear terms
c_float A_x[4] = { 1., 1., 1., 1., }; //constraint coefficients matrix
c_int A_nnz = 4; //number of non zero elements in constraints matrix
c_int A_i[4] = { 0, 1, 0, 2, }; //row indices?
c_int A_p[3] = { 0, 2, 4}; //?
c_float l[3] = { 1., 0., 0., }; //lower bounds
c_float u[3] = { 1., 0.7, 0.7, }; //upper bounds
c_int n = 2; //number of variables (x)
c_int m = 3; //number of constraints
// Problem settings
OSQPSettings *settings = (OSQPSettings *)c_malloc(sizeof(OSQPSettings));
// Structures
OSQPWorkspace *work; // Workspace
OSQPData *data; // OSQPData
// Populate data
data = (OSQPData *)c_malloc(sizeof(OSQPData));
data->n = n;
data->m = m;
data->P = csc_matrix(data->n, data->n, P_nnz, P_x, P_i, P_p);
data->q = q;
data->A = csc_matrix(data->m, data->n, A_nnz, A_x, A_i, A_p);
data->l = l;
data->u = u;
// Define Solver settings as default
osqp_set_default_settings(settings);
// Setup workspace
work = osqp_setup(data, settings);
// Solve Problem
osqp_solve(work);
// Clean workspace
osqp_cleanup(work);
c_free(data->A);
c_free(data->P);
c_free(data);
c_free(settings);
}
}
托管(F#)
open System.Runtime.InteropServices
module ExternalFunctions =
[<DllImport("TestLibCpp.dll")>]
extern void DisplayHelloFromDLL(float[] i)
[<EntryPoint>]
let main argv =
let P_x = [|4.; 1.; 1.; 2.|]
ExternalFunctions.DisplayHelloFromDLL(P_x);
0 // return an integer exit code