C和Fortran互相传递动态数组

C和Fortran的相互调用传递数值的方法有很多,但是F03标准的出笼,使用ISO_C_BINDING进行C和Fortran的互相调用有着更显著的优势:

1、与编译器和平台无关;

2、Fortran中可以定义C的数据类型;

3、使用Interface接口声明,清晰明了;

这里主要介绍C传递动态数组给Fortran的一种解决思路。

C代码:

 1 #include <stdlib.h>   /* malloc */
 2 #include <stdio.h>    /* printf */
 3 struct my_struct{
 4     int num; /* length of array*/
 5     int *array; /* dynamic array*/
 6 }my_struct;
 7 int j=12;
 8 struct my_struct make_array(){
 9     struct my_struct tmp;
10     int i;
11     tmp.num = j;
12     /* initialize array */
13     tmp.array = (int*)malloc(tmp.num*sizeof(int));
14     for(i=0;i<tmp.num;i++)tmp.array[i]=(i+1)*(i+1);
15     j+=3;
16     return tmp;
17 }

Fortran代码:

program f_call_c
use,intrinsic::iso_c_binding
implicit none
! define same struct in C
type,bind(c)::my_struct
integer(c_int)::nn
type(c_ptr)::array
end type
interface
	type(my_struct) function make_array() bind(c,name='make_array')
		import !! Make iso_c_binding and my_struct visible here
	end function
endinterface
integer(C_INT), pointer :: array(:) => NULL()
type(my_struct)::xyz
integer::j
do j=1,3
	xyz = make_array()
	call c_f_pointer(xyz%array,array,[xyz%nn])
	write(*,*)xyz%nn
	write(*,*)array
enddo
end program

==========================================================

2014-03-14 更新 C传递动态数组到Fortran的代码

2014-03-17 补充Fortran传递动态数组到C的代码

1、根据gfortran的使用手册:If a pointer is a dummy-argument of an interoperable procedure, it usually has to be declared using the VALUE attribute. void* matches TYPE(C_PTR), VALUE, while TYPE(C_PTR) alone matches void**.

2、增加的代码在C中定义全局指针用于分配内存开辟动态数组,然后Fortran调用,最后C代码中释放内存

3、gfortran可以直接同时编译c和fortran文件,gcc同样亦可不过需要添加编译参数

小结:推荐使用Function而不是subroutine定义C的interface,分配给动态数组的内存要清空,避免内存泄漏,使用指针的话用完后记得指向空指针。

************************************

C传递动态数组到Fortran

C pass dynamic array to Fortran

************************************

C代码:

#include <stdlib.h>
#include <stdio.h>

// define a struct
-
struct conn{
    int ind;
    float *list;
    int length;
};
// define a pointer struct
struct conn *abc=NULL;
// length of dynamic array
int array_len=0,struct_len=0;
// define a pointer to pointer
float *vector2=NULL;


/* float array printing function */
void print_float_array(float *array, int len)
-
{
    int i;
    for(i=0; i<len; i++)
        printf("%f | ", array[i]);
    putchar('\n');
}
void clear_array(void)
-
{
-
    if(vector2!=NULL){
        free(vector2);
        vector2=NULL;
        printf("Clear pointer successfully\n");
    }
-
    else{
        printf("Already NULL!\n");
    }
}
// Method 1
void dynamic_array(int n1,float **a,int *n2)
-
{
    int i;
    if(vector2!=NULL)clear_array();
    // Allocate array
    vector2 = (float*)malloc(n1*2*sizeof(float));
    // Set values
    for(i=0;i<n1*2;i++){vector2[i] = (float)i*i+1.0;}
    // display array
    print_float_array(vector2,n1*2);
    //
    *a = vector2;
    *n2 = 2*n1;
    // Set length of array
    array_len = n1*2;
}
// Method 2
float* d_array(int n1,int *n2)
-
{
    int i;
    if(vector2!=NULL)clear_array();
    // Allocate array
    vector2 = (float*)malloc(n1*2*sizeof(float));
    // Set values
    for(i=0;i<n1*2;i++){vector2[i] = (float)i*i+1.0;}
    print_float_array(vector2,n1*2);
    *n2 = 2*n1;
    array_len = n1*2;
    return vector2;
}

void clear_struct(void)
-
{
    int i;
-
    if(abc!=NULL){
-
        for(i=0;i<struct_len;i++){
            free(abc[i].list);
            abc[i].list=NULL;
        }
        struct_len = 0;
        free(abc);
        abc = NULL;
        printf("Clear struct array successfully!");
        putchar('\n');
    }
-
    else{
        printf("Already NULL\n");
    }
}
// Pass dynamic struct array
struct conn *d_struct(int n1,int *n2)
-
{
    int i,j;
    if(abc!=NULL)clear_struct();
    // Allocate sturct array
    abc = (struct conn*)malloc((n1+1)*sizeof(struct conn));
    // Set values
-
    for(i=0;i<n1+1;i++){
        abc[i].list = (float*)malloc((i+2)*sizeof(float));
        abc[i].ind = i+1;
        abc[i].length = i+2;
-
        for(j=0;j<i+2;j++){
            abc[i].list[j] = (float)j*j+0.5;
        }
    }
    *n2 = n1 + 1;
    struct_len = n1 + 1;
    return abc;
}

Fortran代码: 

- module dynamic
use,intrinsic::iso_c_binding
implicit none
! Define struct
-
type,bind(c)::connect
    integer(c_int)::ind
    type(c_ptr)::list
    integer(c_int)::length
end type
-
interface
    ! Method 1 via subroutine
-
    subroutine dynamic_array(length,a,n)bind(c,name='dynamic_array')
    import
    implicit none
    integer(c_int),intent(in),value::length
    integer(c_int),intent(out)::n
    type(c_ptr),intent(out)::a
    end subroutine
    ! Mehtod 2 via function
-
    type(c_ptr) function dynamic_array2(length,n)bind(c,name='d_array')
    import
    implicit none
    integer(c_int),intent(in),value::length
    integer(c_int),intent(out)::n
    end function
    ! Pass dynamic struct array via function
-
    type(c_ptr) function dynamic_struct(length,n)bind(c,name='d_struct')
    import
    implicit none
    integer(c_int),intent(in),value::length
    integer(c_int),intent(out)::n
    end function
    ! Clear struct array
-
    subroutine clear_struct()bind(c,name='clear_struct')
    import
    implicit none
    end subroutine
    ! Clear array
-
    subroutine clear_array()bind(c,name='clear_array')
    import
    implicit none
    end subroutine
end interface
end module

-
program test
use dynamic
implicit none
real,pointer::array(:)
integer,pointer::nn
type(c_ptr)::c_array,c_struct
type(connect),pointer::conn(:)
integer::i,j,k
nullify(array)
nn
=>NULL()
c_array
=c_null_ptr
i
= 10
j
= 0
call dynamic_array(i,c_array,j)
!c_array = dynamic_array2(i,j)
write(*,*)i,j
call c_f_pointer(c_array,array,[j])
write(*,*)
write(*,*)array
c_array
=c_null_ptr
c_struct
= c_null_ptr
array
=>null()
i
= 2*2
j
= 0
c_struct
= dynamic_struct(i,j)
write(*,*)i,j
call c_f_pointer(c_struct,conn,[j])
-
do i=1,j
    array=>null()
    call c_f_pointer(conn(i)%list,array,[conn(i)%length])
    write(*,*)"Index:",i
    write(*,*)"List:",(array(k),k=1,size(array))
enddo
call clear_struct()
call clear_array()
end program

************************************

Fortran传递动态数组到C

Fortran pass dynamic array to C

***********************************

Fortran代码:

- module f2c_dynamic
use,intrinsic::iso_c_binding
implicit none
integer(c_int),allocatable,target::ind(:)
contains
-
    type(c_ptr) function init_array(n1,n2)bind(c,name="allocArray")
    implicit none
    integer(c_int),intent(in),value::n1
    integer(c_int),intent(out)::n2
    integer::i
    write(*,*)"************************"
    write(*,*)"Fortran"
    write(*,*)"************************"
    write(*,*)"input:",n1,n2
    call clear_array()
    init_array = c_null_ptr
    allocate(ind(n1+6))
-
    do i=1,n1+6
        ind(i) = i**2+2
        write(*,*)"index:",i," value:",ind(i)
    enddo
    n2 = n1 + 6
    write(*,*)"array size:",n2
    init_array = c_loc(ind(1))
    write(*,*)"Return pointer"
    return
    end function
   
-
    subroutine init_array2(n1,n2,a)bind(c,name="allocArray2")
    implicit none
    integer(c_int),intent(in),value::n1
    integer(c_int),intent(out)::n2
    type(c_ptr),intent(out)::a
    integer::i
    write(*,*)"************************"
    write(*,*)"Fortran"
    write(*,*)"************************"
    write(*,*)"input:",n1,n2
    call clear_array()
    a = c_null_ptr
    allocate(ind(n1+2))
-
    do i=1,n1+2
        ind(i) = i**3-1
        write(*,*)"index:",i," value:",ind(i)
    enddo
    n2 = n1 + 2
    write(*,*)"array size:",n2
    a = c_loc(ind(1))
    write(*,*)"Return pointer"
    return
    end subroutine
-
    subroutine clear_array()bind(c,name="clearArray")
    implicit none
    if(allocated(ind))then
        deallocate(ind)
        write(*,*)"Clear successfully"
    endif
    end subroutine
end module f2c_dynamic

C代码:

 #include <stdlib.h>   /* malloc */
 
#include <stdio.h>    /* printf */
 
 
int *allocArray(int ,int *);// via fortran function
 
void allocArray2(int,int *,int **);// via fortran subroutine
 
void clearArray();
 
 
/* float array printing function */
 
void print_int_array(int *array, int len)
-
{
 
    int i;
 
    for(i=0; i<len; i++)
 
        printf("%d | ", array[i]);
 
    putchar('\n');
 
}
 
int main(int argc,char *argv[])
-
{
 
    int n1=5;
 
    int n2=0;
 
    int *a=NULL;
 
    int *b=NULL;
 
    a=allocArray(n1,&n2);
 
    printf("********************\nC output\ninput:%d size:%d\n",n1,n2);
 
    print_int_array(a,n2);
 
    clearArray();
 
    n2 = 0;
 
    n1 = 6;
 
    allocArray2(n1,&n2,&b);
 
    printf("********************\nC output\ninput:%d size:%d\n",n1,n2);
 
    print_int_array(b,n2);
 
    clearArray();
 
    a=NULL;
 
    b=NULL;
 
    return 0;
 
}

posted @ 2013-10-10 11:34  pasuka  阅读(3652)  评论(0编辑  收藏  举报