gpt4 book ai didi

arrays - Fortran:指针数组数组?

转载 作者:行者123 更新时间:2023-12-01 15:43:21 25 4
gpt4 key购买 nike

我正在使用一些 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

地点:

VarLoc(i) 是一个表示内存位置的整数

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

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

作为引用,Fortran 代码以自由形式编写并使用了英特尔编译器

感谢您的帮助!

最佳答案

好的,所以我假设冒号与续行有关并忽略它们,而您正在尝试这样做:

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

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

我不认为在 Fortran 端进行 C 指针运算是个好主意,但是。

因此,您希望 VarNames_ 成为一个包含 5 个指针的数组,这些指针指向 3.. 一些东西,您没有说。比方说整数。

让我们从简单的案例来看:假设我们在 C 语言中有一个一维整数数组,并且想要在 Fortran 语言中指向它们的指针。如果我们的 C 例程是这样的 (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;
}

我们的 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

和这样的 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

然后构建并运行它,我们得到了预期的答案:

$ ./main 
fdata = 0 1 2 3 4

请注意,在 C 中,我们分配了一个包含 5 个整数的数组; Fortran 程序主要定义 C 例程的接口(interface),因此我们可以从 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)

但我真的不推荐这个;最好在 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)

更干净,不太可能导致奇怪的错误,也更小!

好的,最后,让我们做一个指针数组。诚然,这比在 Fortran 中应该做的要难,因为 Fortran 不容易让您定义指针数组;您必须创建一个已定义的类型(Fortran 相当于 C 中的结构)。但这很容易。让我们按照我推荐的方式做事,在 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)

这里我们创建了一个 ptrelelment 类型,它是一个一维指针数组,然后创建了一个数组。这为我们提供了指针数组,我们通过获取 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

或者,正如我建议的那样,在 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)

关于arrays - Fortran:指针数组数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6998995/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com