zoukankan      html  css  js  c++  java
  • 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(' ');
    }
    void clear_array(void)
    -
    {
    -
        if(vector2!=NULL){
            free(vector2);
            vector2=NULL;
            printf("Clear pointer successfully ");
        }
    -
        else{
            printf("Already NULL! ");
        }
    }
    // 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(' ');
        }
    -
        else{
            printf("Already NULL ");
        }
    }
    // 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(' ');
     
    }
     
    int main(int argc,char *argv[])
    -
    {
     
        int n1=5;
     
        int n2=0;
     
        int *a=NULL;
     
        int *b=NULL;
     
        a=allocArray(n1,&n2);
     
        printf("******************** C output input:%d size:%d ",n1,n2);
     
        print_int_array(a,n2);
     
        clearArray();
     
        n2 = 0;
     
        n1 = 6;
     
        allocArray2(n1,&n2,&b);
     
        printf("******************** C output input:%d size:%d ",n1,n2);
     
        print_int_array(b,n2);
     
        clearArray();
     
        a=NULL;
     
        b=NULL;
     
        return 0;
     
    }

  • 相关阅读:
    大数据时代的艺术金融
    与“数”同行:大数据驱动大学变革
    与“数”同行:大数据驱动大学变革
    财务信息化:大数据小时代
    财务信息化:大数据小时代
    Python导出DBF文件到Excel的方法
    Python导出DBF文件到Excel的方法
    SolrJ的入门
    Spring Data Solr入门
    使用solr进行配置文件
  • 原文地址:https://www.cnblogs.com/pasuka/p/3360928.html
Copyright © 2011-2022 走看看