我的主要问题是为什么数组会做如此奇怪的事情,以及是否有任何方法可以以“干净”的方式执行以下操作。
我目前有一个C程序foo.c
连接 Fortran 程序bar.f90
via dlopen/dlsym
,大致如下面的代码所示:
foo.c:
#include <dlfcn.h>
#include <stdio.h>
int main()
{
int i, k = 4;
double arr[k];
char * e;
void * bar = dlopen("Code/Test/bar.so", RTLD_NOW | RTLD_LOCAL);
void (*allocArray)(int*);
*(void **)(&allocArray) = dlsym(bar, "__bar_MOD_allocarray");
void (*fillArray)(double*);
*(void **)(&fillArray) = dlsym(bar, "__bar_MOD_fillarray");
void (*printArray)(void);
*(void **)(&printArray) = dlsym(bar, "__bar_MOD_printarray");
double *a = (double*)dlsym(bar, "__bar_MOD_a");
for(i = 0; i < k; i++)
arr[i] = i * 3.14;
(*allocArray)(&k);
(*fillArray)(arr);
(*printArray)();
for(i = 0; i < 4; i++)
printf("%f ", a[i]);
printf("\n");
return 0;
}
bar.f90:
module bar
integer, parameter :: pa = selected_real_kind(15, 307)
real(pa), dimension(:), allocatable :: a
integer :: as
contains
subroutine allocArray(asize)
integer, intent(in) :: asize
as = asize
allocate(a(asize))
return
end subroutine
subroutine fillArray(values)
real(pa), dimension(as), intent(in) :: values
a = values
return
end subroutine
subroutine printArray()
write(*,*) a
return
end subroutine
end module
运行主要收益率
0.0000000000000000 3.1400000000000001 6.2800000000000002 9.4199999999999999
0.000000 -nan 0.000000 0.000000
这表明 Fortran 正确分配了数组,甚至正确存储了给定值,但无法再通过 dlsym 访问它们(处理该数据会导致段错误)。我也尝试过对固定大小的数组进行此操作 - 结果保持不变。
有谁知道这种行为的原因?我个人预计事情要么是双向的,要么根本不工作——这个“Fortran 接受 C 数组,但反之亦然”让我想知道我以这种方式从 C 访问数组时是否犯了一些基本错误。
另一个(也是更重要的)问题是,如何“以正确的方式”进行这样的数组访问。目前我什至不确定坚持使用“Fortran as .so”接口是否是一个好方法 - 我认为在这种情况下也可以尝试混合编程。尽管如此,数组问题仍然存在 - 我读到可以使用 ISO C 绑定以某种方式解决这个问题,但我还不知道如何解决(我还没有大量使用 Fortran,尤其是没有使用所述绑定) ,因此我们将不胜感激有关此问题的帮助。
Edit:
好的,所以我详细阅读了 ISO C 绑定,发现了一个非常有用的方法here https://stackoverflow.com/questions/9677972/how-to-allocate-an-array-inside-fortran-routine-called-from-c. Using C_LOC
我可以获得指向我的 Fortran 结构的 C 指针。不幸的是,指向数组的指针似乎是指向指针的指针,需要在 C 代码中取消引用,然后才能将其视为 C 数组 - 或类似的东西。
Edit:
现在我的程序按照 Vladimir F 指出的方式使用 C 绑定来工作,至少在大部分情况下是这样。 C 文件和 Fortran 文件现在链接在一起,因此我可以避免使用 libdl 接口,至少对于 Fortran 部分 - 我仍然需要加载动态 C 库,获取指向其中符号之一的函数指针并传递该指针作为指向 Fortran 的函数指针,Fortran 随后调用该函数作为其计算的一部分。正如所述函数需要 double*s [arrays],我无法设法使用 C_LOC 传递我的 Fortran 数组,奇怪的是 - 两者都没有C_LOC(array)
nor C_LOC(array(1))
将正确的指针传递回 C 函数。array(1)
不过还是成功了。遗憾的是,这不是“最干净”的方法。如果有人提示我如何使用C_LOC
功能,那就太好了。尽管如此,我接受弗拉基米尔 F 的回答,因为我认为这是更安全的解决方案。