Fortran Coder

查看: 13836|回复: 6
打印 上一主题 下一主题

[混编] 从C传递数组到Fortran

[复制链接]

490

帖子

4

主题

0

精华

大宗师

F 币
3298 元
贡献
1948 点

水王勋章元老勋章热心勋章

跳转到指定楼层
楼主
发表于 2014-3-12 23:06:02 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
问题:
从C传递数组到Fortran,分别通过interface定义了subroutine和function的形式,前者未起作用,而后者却可以
编译器:gcc/gfortran 4.7&4.8
fortran代码:
[Fortran] 纯文本查看 复制代码
01module dynamic
02use,intrinsic::iso_c_binding
03implicit none
04interface
05  ! Method 1: pass array via subroutine
06  subroutine dynamic_array(length,a,n)bind(c,name='dynamic_array')
07  import
08  implicit none
09  integer(c_int),intent(in),value::length
10  integer(c_int),intent(out)::n
11  type(c_ptr),intent(out)::a
12  end subroutine
13  ! Mehtod 2: pass array via funciton
14  type(c_ptr) function dynamic_array2(length,n)bind(c,name='d_array')
15  import
16  implicit none
17  integer(c_int),intent(in),value::length
18  integer(c_int),intent(out)::n
19  end function
20end interface
21end module
22program test
23use dynamic
24implicit none
25real,pointer::array(:)
26type(c_ptr)::c_array
27real(c_float),allocatable::array2(:)
28integer::i,j
29! Initialize pointer
30nullify(array)
31c_array=c_null_ptr
32 
33i=10
34j=0
35! Method 1
36! not worked
37call dynamic_array(i,c_array,j)
38 
39call c_f_pointer(c_array,array,[j])
40write(*,'(A)')"Pass by subroutine"
41write(*,'(A,i4)')"Len of array:",j
42write(*,'(A)')"Array values:"
43write(*,*)array
44c_array=c_null_ptr
45array=>null()
46 
47i = 10
48j = 0
49! Method2
50! worked
51c_array = dynamic_array2(i,j)
52call c_f_pointer(c_array,array,[j])
53write(*,'(A)')"Pass by function"
54write(*,'(A,i4)')"Len of array:",j
55write(*,'(A)')"Array values:"
56write(*,*)array
57c_array=c_null_ptr
58array=>null()
59 
60end program

C代码:
[C] 纯文本查看 复制代码
01#include <stdlib.h>
02#include <stdio.h>
03/* float array printing function */
04void print_float_array(float *array, int len)
05{
06    int i;
07    for(i=0; i<len; i++)
08        printf("%f | ", array[i]);
09    putchar('\n');
10}
11 
12void dynamic_array(int n1,float *a,int *n2)
13{
14  int i;
15  // allocate array
16  a = (float*)malloc(n1*2*sizeof(float));
17  // set values of array
18  for(i=0;i<n1*2;i++){a[i] = (float)i*i+1.0;}
19  //print_float_array(a,n1*2);
20  // set length of array
21  *n2 = 20;
22}
23 
24float* d_array(int n1,int *n2)
25{
26  int i;
27  float *a;
28  // allocate array
29  a = (float*)malloc(n1*2*sizeof(float));
30  // set value
31  for(i=0;i<n1*2;i++){a[i] = (float)i*i+1.0;}
32  //print_float_array(a,n1*2);
33  // set len of array
34  *n2 = 20;
35  return a;
36}


分享到:  微信微信
收藏收藏 点赞点赞 点踩点踩

742

帖子

4

主题

0

精华

大师

农村外出务工人员

F 币
726 元
贡献
371 点

新人勋章爱心勋章水王勋章元老勋章热心勋章

沙发
发表于 2014-3-13 00:43:40 | 只看该作者
本帖最后由 chuxf 于 2014-3-13 01:16 编辑

我把 float *a 改成 float **a 以后就可以正常运行了。

因为平时用 Binding 模块少,不太清楚具体如何规定。但是跟踪调试发现,c_ptr 实际上是一个有一个指针成员的结构体,因为 Fortran 传递是传址的。所以指针的地址,就是指针的指针。故而,c 里面应该用 float **a

仅站在 C 语言的角度,如果函数内分配空间,传递给调用者,也必须用指针的指针。


第二个程序用function就正常。那是因为fortran对返回值并不做任何处理,返回什么,就当什么。
d_array 中 a 是指针,返回Fortran以后,它依然是指针,于是 c_array 指针指向正确。

总结来说,Fortran调用一个函数,给它一个参数,一定是参数的地址(传址)。而被调用者返还的返回值,则不做处理。

[C] 纯文本查看 复制代码
01void dynamic_array(int n1, float **a, int *n2)
02{
03  int i;
04  // allocate array
05  *a = (float*)malloc(n1 * 2 * sizeof(float));
06  // set values of array
07  for (i = 0; i<n1 * 2; i++){ (*a)[i] = (float)i*i + 1.0; }
08  //print_float_array(a,n1*2);
09  // set length of array
10  *n2 = 20;
11}

69

帖子

7

主题

0

精华

专家

F 币
320 元
贡献
224 点
板凳
发表于 2014-3-13 09:11:18 | 只看该作者
chuxf 发表于 2014-3-13 00:43
我把 float *a 改成 float **a 以后就可以正常运行了。

因为平时用 Binding 模块少,不太清楚具体如何规定 ...

type(c_ptr),value 对应C的 void*,type(c_ptr)对应C的 void**,详见gfortran的manual。

490

帖子

4

主题

0

精华

大宗师

F 币
3298 元
贡献
1948 点

水王勋章元老勋章热心勋章

地板
 楼主| 发表于 2014-3-13 09:14:54 | 只看该作者
chuxf 发表于 2014-3-13 00:43
我把 float *a 改成 float **a 以后就可以正常运行了。

因为平时用 Binding 模块少,不太清楚具体如何规定 ...

多谢达人
终于搞明白这个问题了

69

帖子

7

主题

0

精华

专家

F 币
320 元
贡献
224 点
5#
发表于 2014-3-13 09:27:14 | 只看该作者
本帖最后由 jason388 于 2014-3-13 09:30 编辑

即使运行正常也不应该像楼主这样使用。无论是Fortran还是C的动态内存分配,一般均应该分配/释放成对使用,以避免内存泄漏。因此,如果主程序为Fortran,则全局变量的内存分配和释放应该由Fortran负责,同样如果主程序为C则全局变量的内存分配和释放应该由C负责,当然函数内的局部变量的内存分配和释放不在此列。

按Fortran2003标准,Fortran的可分配数组和指针与C是不能互操作的,但TS 29113 Further Interoperability of Fortran with C通过ISO_Fortran_binding.h等使这些限制得以消除,遗憾的是目前gfotran还不能完全支持TS29113.

742

帖子

4

主题

0

精华

大师

农村外出务工人员

F 币
726 元
贡献
371 点

新人勋章爱心勋章水王勋章元老勋章热心勋章

6#
发表于 2014-3-13 12:08:30 | 只看该作者
楼上说得很对,谁申请,谁释放;谁打开,谁关闭。这样才不容易出错。

137

帖子

37

主题

0

精华

宗师

F 币
1626 元
贡献
825 点
7#
发表于 2018-5-16 14:34:06 | 只看该作者
从此坑中爬出来的福友路过!
您需要登录后才可以回帖 登录 | 极速注册

本版积分规则

捐赠本站|Archiver|关于我们 About Us|小黑屋|Fcode ( 京ICP备18005632-2号 )

GMT+8, 2025-4-29 06:43

Powered by Discuz! X3.4

© 2013-2025 Comsenz Inc.

快速回复 返回顶部 返回列表