如何访问(动态分配)用C Fortran数组 [英] How to access (dynamically allocated) Fortran arrays in C

查看:543
本文介绍了如何访问(动态分配)用C Fortran数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的主要问题是,为什么阵列做这种怪异的东西,以及是否有做一个干净的方式下列任何方式都没有。

My main question is why arrays do such weird things and whether there is any way at all to do the following in a "clean" way.

我现在有一个C程序 foo.c的通过<$ C $接口Fortran程序 bar.f90 C>的dlopen / dlsym进行,大致是如下code:

I currently have a C program foo.c interfacing a Fortran program bar.f90 via dlopen/dlsym, roughly like in the code below:

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再访问(在段错误上的数据的结果的工作)。我也试过这个固定大小的数组 - 的结果保持不变。

which shows that Fortran allocates the array correctly and even correctly stores the given values but they are not accessible via dlsym anymore (working on that data results in segfaults). I also tried this for fixed-size arrays - the results stay the same.

有谁知道这种行为的原因是什么?我个人而言,本来期望的东西要么制定出双向或替代根本 - 这的Fortran接受C数组而不是相反使我怀疑是否有一些基本的错误,我在访问从C数组以这种方式进行。

Does anyone know the reason for this behaviour? I, personally, would have expected things to either work out bidirectional or alternatively not at all - this "Fortran accepting C arrays but not vice versa" makes me wonder whether there's some basic mistake I made on accessing the array from C in this fashion.

其他的(甚至更重要)的问题是,如何做数组访问像这些正确的方式。目前,我甚至不知道是否坚持了的Fortran作为。所以接口是所有的好办法 - 我想这也将有可能试图在这种情况下,混合编程。尽管如此,阵列问题仍然是 - 我读这可以在某种程度上使用ISO C绑定来解决,但我无法弄清楚如何,但(我没有工作了很多的Fortran,但是,尤其不能与所述绑定) ,这样有利于对这个问题将大大AP preciated。

The other (and even more important) question is, how to do array accesses like these "the right way". Currently I'm not even sure if sticking to the "Fortran as .so" interface is a good way at all - I think it would also be possible to attempt mixed programming in this case. Nonetheless, the arrays issue remains - I read that this could be solved somehow using the ISO C Binding, but I couldn't figure out how, yet (I haven't worked a lot with Fortran, yet, especially not with said Binding), so help on this issue would be greatly appreciated.

编辑:

好吧,所以我读入ISO C绑定多一点,发现了一个非常有用的方法<一href=\"http://stackoverflow.com/questions/9677972/how-to-allocate-an-array-inside-fortran-routine-called-from-c\">here.使用 C_LOC 我能得到C指针到我的Fortran语言结构。不幸的是,指向数组的指针似乎指向指针的指针,并需要在C code到解除引用才可以作为treates C数组 - 或者类似的东西。

Okay, so I read into the ISO C Binding a little more and found a quite useful approach here. Using C_LOC I can get C pointers to my Fortran structures. Unfortunately, pointers to arrays seem to be pointers to pointers and need to be dereferenced in the C code before they can be treates as C arrays - or something like that.

编辑:

得到了我的计划,现在用C结合的方式弗拉基米尔˚F指出,至少在大多数情况下工作。 C文件和Fortran文件现在是连在一起的,这样我就可以避开libdl接口,至少在Fortran语言的一部分 - 我还需要加载动态C库,在那里,通过获得一个函数指针的标志之一是作为函数指针的Fortran,后来调用函数作为其计算的一部分。至于说功能预计双* S [数组],我无法管理使用我的Fortran数组C_LOC,奇怪的传递 - 既不 C_LOC(阵列)也不 C_LOC(阵列(1))传递正确的指针回C函数。 阵列(1)的伎俩虽然。可悲的是,这是不是最干净的方式来做到这一点。如果任何人有一个提示,我如何做到这一点使用 C_LOC 的功能,那将是巨大的。不过我接受弗拉基米尔·F公司的答案,因为我认为它是更安全的解决方案。

Got my program to work now using C binding the way Vladimir F pointed out, at least for the most part. The C file and Fortran files are now linked together, so I can avoid the libdl interface, at least for the Fortran part - I still need to load a dynamic C library, get a function pointer to one of the symbols in there and pass that as a function pointer to Fortran, which later calls that function as part of its calculation. As said function expects double*s [arrays], I couldn't manage to pass my Fortran arrays using C_LOC, strangely - neither C_LOC(array) nor C_LOC(array(1)) passed the correct pointers back to the C function. array(1) did the trick though. Sadly, this isn't the "cleanest" way to do this. If anyone got a hint for me how to do this using the C_LOC function, that would be great. Nonetheless I accept Vladimir F's answer, as I deem it to be the safer solution.

推荐答案

在我看来,这是不好的做法,尝试用Fortran库访问全局数据。它可以使用通用模块来完成,但他们是邪恶的,需要静态大小的数组。一般存储协会是一件坏事。

In my opinion it is not good practice to try to access global data in Fortran library. It can be done using COMMON blocks, but they are evil and require statically sized arrays. Generally storage association is a bad thing.

从不访问模块的符号为__bar_MOD_a它们是编译器的具体和并不意味着被直接使用。使用函数和子程序poiters通过。

Never access the module symbols as "__bar_MOD_a" they are compiler specific and not meant to be used directly. Pass poiters using functions and subroutines.

传递数组作为子程序的参数。您也可以分配数组中的C和它传递给Fortran语言。什么也可以做的是得到一个指针数组的第一个元素。它将成为ES的C指针数组。

Pass the array as a subroutine argument. You can also allocate the array in C and pass it to Fortran. What can be also done is getting a pointer to the first element of the array. It will serve es the C pointer to the array.

我的解决办法,因为没有了。所以简单,它是微不足道的添加:

My solution, for simplicity without the .so, it is trivial to add it:

bar.f90

module bar
 use iso_C_binding

implicit none

integer, parameter :: pa = selected_real_kind(15, 307)

real(pa), dimension(:), allocatable,target :: a
integer :: as

contains

subroutine allocArray(asize,ptr) bind(C,name="allocArray")
    integer, intent(in) :: asize
    type(c_ptr),intent(out) :: ptr

    as = asize
    allocate(a(asize))

    ptr = c_loc(a(1))
end subroutine

subroutine fillArray(values) bind(C,name="fillArray")
    real(pa), dimension(as), intent(in) :: values

    a = values
end subroutine

subroutine printArray()  bind(C,name="printArray")

    write(*,*) a
end subroutine

end module

的main.c

main.c

#include <dlfcn.h>
#include <stdio.h>

int main()
{
int i, k = 4;
double arr[k];
char * e;
double *a;
void allocArray(int*,double**);
void fillArray(double*);
void allocArray();


for(i = 0; i < k; i++)
    arr[i] = i * 3.14;

allocArray(&k,&a);
fillArray(arr);
printArray();
for(i = 0; i < 4; i++)
    printf("%f ", a[i]);
printf("\n");

return 0;
}

编译并运行:

gcc -c -g main.c

gfortran -c -g -fcheck=all bar.f90

gfortran main.o bar.o

./a.out
0.0000000000000000        3.1400000000000001        6.2800000000000002        9.4199999999999999     
0.000000 3.140000 6.280000 9.420000 

注:没有理由在你的Fortran子程序的回报,他们只模糊了code

Note: There is no reason for the returns in your Fortran subroutines, they only obscure the code.

这篇关于如何访问(动态分配)用C Fortran数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆