Fortran:指针数组的数组?

qu1*_*dry 2 arrays fortran

我正在使用一些Fortran代码(在此项目之前我从未使用过这个代码......)并且遇到了一个问题.我需要与另一个程序共享一些内存空间.为了让Fortran识别每个内存块,我使用以下代码:

       do 10 i = 0, 5 
       CALL C_F_POINTER(TRANSFER(memory_location +
       : VarNamesLoc_(i), 
       : memory_location_cptr) , VarNames_(i), [3]) 
       exit 
    10 continue
Run Code Online (Sandbox Code Playgroud)

哪里:

VarLoc(i)是表示存储器位置的整数

VarNames(i)?指针数组的数组?

我遇到的问题是创建指针数组的VarNames数组.我从谷歌搜索中找到了一些示例代码,但我发现Fortran很难理解!! 任何人都可以告诉我如何设置指针数组的数组?或者如果我不正确地接近问题,请指出替代方案?

作为参考,Fortran代码是以自由形式编写的,并使用intel编译器

谢谢你的帮助!

Jon*_*rsi 8

好的,所以我要假设冒号与延续线有关并忽略它们,而你正试图这样做:

do i = 0, 5 
    CALL C_F_POINTER(&
          TRANSFER(memory_location + VarNamesLoc_(i), memory_location_cptr), &
          VarNames_(i), [3] ) 
enddo 
Run Code Online (Sandbox Code Playgroud)

这样做是:(TRANSFER)取一个表示现有C指针的整数(我假设)memory_location,向该(VarNamesLoc_(i))添加一个偏移量,并将其转换为一种类型c_ptr.然后(C_F_POINTER)将其转换为形状[3]的Fortran指针.

我不认为在Fortran端做C指针算法是一个好主意,但是.

所以你想要VarNames_成为一个由3个数组组成的5个指针的数组...你还没有说过.让我们说整数.

让我们从简单的例子中得出结论:让我们说我们在C中有一个1维的int数组,并希望在Fortran中有一个指向它们的指针.如果我们的C例程是this(croutine.c):

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

void makearray(int **data, int n) {
    *data = (int *)malloc(n * sizeof(int));
    for (int i=0; i<n; i++) 
        (*data)[i] = i;
    return;
}

void freearray(int **data, int n) {
    free(*data);
    return;
}
Run Code Online (Sandbox Code Playgroud)

我们的Fortran驱动程序可能如下所示(driver.f90):

PROGRAM interoptesting
    USE, intrinsic :: iso_c_binding
    USE, intrinsic :: iso_fortran_env
    IMPLICIT NONE

    INTERFACE
        !! C prototype: void makearray(int **data, int n)
        SUBROUTINE makearray(data, n) BIND(C)
            USE, intrinsic :: iso_c_binding
            type(c_ptr)    :: data
            integer(kind=c_int), value :: n
        END SUBROUTINE makearray
        !! C prototype: void freearray(int **data, int n)
        SUBROUTINE freearray(data, n) BIND(C)
            USE, intrinsic :: iso_c_binding
            type(c_ptr)    :: data
            integer(kind=c_int), value :: n
        END SUBROUTINE freearray
    END INTERFACE 

    type(c_ptr) :: cdata
    integer, pointer, dimension(:) :: fdata
    integer                        :: n = 5

    call makearray(cdata, n);
    call c_f_pointer(cdata, fdata, [n])
    print *, 'fdata = ', fdata
    call freearray(cdata, n)

END program
Run Code Online (Sandbox Code Playgroud)

和这样的Makefile:

FC=gfortran
CC=gcc
CFLAGS=-std=c99 -g
FFLAGS=-g

main: driver.o croutine.o 
        $(FC) -o $@ $^

driver.o: driver.f90
        $(FC) $(FFLAGS) -c $<

clean:
        rm -rf main driver.o croutine.o 
Run Code Online (Sandbox Code Playgroud)

并建立并运行它我们得到预期的答案:

$ ./main 
 fdata =            0           1           2           3           4
Run Code Online (Sandbox Code Playgroud)

注意,在C中我们分配了一个5个整数的数组; Fortran程序主要定义了C例程的接口,因此我们可以从Fortran调用它们,然后调用它们.它c_f_pointer执行c指针(cdata)和Fortran指针(fdata)之间的转换.

如果我们想在Fortran中做一些C指针算术,我们可以这样做:

type(c_ptr) :: cdata, newdata
integer(kind=int64)            :: tmpint
integer, pointer, dimension(:) :: fdata
integer                        :: n = 5
integer(kind=c_int) :: cint

call makearray(cdata, n);

! copy pointer to an int
tmpint = TRANSFER(cdata, tmpint)
! add two integer sizes:
tmpint = tmpint + 2*c_sizeof(cint)
! copy back into a pointer
newdata= TRANSFER(tmpint, newdata)

call c_f_pointer(newdata, fdata, [n-2])
print *, 'fdata = ', fdata
call freearray(cdata, n)
Run Code Online (Sandbox Code Playgroud)

但我真的不推荐这个; 最好在Fortran中进行指针操作:

type(c_ptr) :: cdata
integer, pointer, dimension(:) :: fdata, newfdata
integer                        :: n = 5

call makearray(cdata, n);
call c_f_pointer(cdata, fdata, [n])

newfdata => fdata(3:n)
print *, 'newfdata = ', newfdata
call freearray(cdata, n)
Run Code Online (Sandbox Code Playgroud)

更清洁,不太可能导致错误的错误,也更小!

好的,最后,让我们做一个指针数组.诚然,这比在Fortran中应该更难,因为Fortran不容易让你定义指针数组; 你必须创建一个已定义的类型(在C中的Fortran等效结构).但这很容易.让我们按照我推荐的方式做事,在Fortran端进行指针数学运算:

type(c_ptr) :: cdata
integer, pointer, dimension(:) :: fdata
integer                        :: n = 10
integer, parameter             :: nptrs = 5
integer :: i, intsperptr, istart, iend

! our new "ptrelement" type which we can define arrays of
type ptrelement
     integer, pointer, dimension(:) :: p
end type ptrelement
type(ptrelement) :: ptrs(nptrs)

call makearray(cdata, n);
call c_f_pointer(cdata, fdata, [n])

intsperptr = n/nptrs
do i=1,nptrs
    istart = (i-1)*intsperptr+1
    iend   = istart + intsperptr-1
    ptrs(i)%p => fdata(istart:iend)
enddo

do i=1,nptrs
    print '(A,I2,A,99(I5,X))', 'ptrs(',i,')%p = ', ptrs(i)%p
enddo

call freearray(cdata, n)
Run Code Online (Sandbox Code Playgroud)

这里我们创建了ptrelelment一个1-d指针数组的类型,然后创建了一个数组.这给了我们指针数组,我们通过切片来设置它fdata,它仍然是指向整个数据的指针.

跑步给了我们

$ ./main
ptrs( 1)%p =     0     1
ptrs( 2)%p =     2     3
ptrs( 3)%p =     4     5
ptrs( 4)%p =     6     7
ptrs( 5)%p =     8     9
Run Code Online (Sandbox Code Playgroud)

或者,正如我建议的那样,在Fortran中进行C风格的指针数学运算:

type(c_ptr) :: cdata
integer                        :: n = 10
integer, parameter             :: nptrs = 5
integer :: i, intsperptr
integer(kind=c_int) :: cint
integer(kind=int64) :: cdata_as_int

! our new "ptrelement" type which we can define arrays of
type ptrelement
     integer, pointer, dimension(:) :: p
end type ptrelement
type(ptrelement) :: ptrs(nptrs)

call makearray(cdata, n);
cdata_as_int = TRANSFER(cdata, cdata_as_int)

intsperptr = n/nptrs
do i=1,nptrs
    call c_f_pointer( &
         TRANSFER(cdata_as_int + (i-1)*intsperptr*c_sizeof(cint), cdata),&
         ptrs(i)%p, [intsperptr] )
enddo

do i=1,nptrs
    print '(A,I2,A,99(I5,X))', 'ptrs(',i,')%p = ', ptrs(i)%p
enddo

call freearray(cdata, n)
Run Code Online (Sandbox Code Playgroud)