在C中为fortran数组分配内存

我是fortran编程的新手。我有一个3维数组声明如下

REAL*4, DIMENSION(:,:,:), ALLOCATABLE :: a1 

我想通过引用C或C ++函数传递数组,并在C而不是fortran中分配内存。 在fortran中理解数组概念是否可能或我错了?

这取决于您的具体情况,但可能不是。 绝对不是以便携方式,如果您根据问题标签限制为Fortran 90。

请注意,您的Fortran变量是ALLOCATABLE。

正如您所问,它需要Fortran编译器(和配套C编译器)来实现最近发布的技术规范(T229113:2012)。 您正处于语言开发的最前沿 – 目前支持此TS的编译器数量很少(如果不是零)。 预计此TS的内容将被纳入Fortran标准的下一版本,因此请在几年后再试一次,您可能会有更好的运气。

但请注意,TS限制了C可以为Fortran分配的方式 – 基本上C代码需要调用Fortran编译器提供的例程。 你不能使用任何旧的分配器(包括malloc),所以这仍然不适合。

但是,Fortran 2003增加了在C中完成Fortran POINTER(不是可分配的内存)的内存分配的可能性.C代码返回指向适当大小的一块内存的指针,Fortran程序收到返回作为C_PTR类型的对象。 然后,Fortran代码调用过程C_F_POINTER将C_PTR对象中的C地址与Fortran指针相关联。 C_PTR和C_F_POINTER是内部ISO_C_BINDING模块中的实体。

一个粗略的例子:

 USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_PTR, C_F_POINTER INTERFACE FUNCTION get_some_memory() BIND(C, NAME='get_some_memory') IMPORT :: C_PTR TYPE(C_PTR) :: get_some_memory END FUNCTION get_some_memory END INTERFACE ! REAL*4 isn't Fortran. Correct syntax below. REAL(4), POINTER, DIMENSION(:,:,:) :: a1 ! get_some_memory would typically be told how much memory was needed. ! n1, n2, n3 are integer with the relevant extents for each dimension. CALL C_F_POINTER(get_some_memory(), a1, [n1,n2,n3]) ! Equivalent call to free required at some later stage. void *get_some_memory() { return malloc(some_number_of_bytes); } 

除此之外,您还可以使用与处理器相关的(即非便携式)技巧,但它们不在标准语言之内。

正如IanH的回答所说,技术规范TS 29113允许在C函数中执行Fortran可分配对象的分配方式,这对Fortran端具有持久影响。

由于之前的答案是书面支持这个TS已经增加(虽然它仍然不大,我们将在这个答案中使用的C描述符部分显然不受当前gfortran的支持)。 这意味着它现在可能值得写一个例子。 此示例在Fortran 2008下无效。

我们考虑CFI_desc_t (来自源文件ISO_Fortran_binding.h )和C函数CFI_allocate给出的C结构。

假设我们对rank-3arrays的分配发生在与以下Fortran接口兼容的C过程中

 interface subroutine allocating_sub(x) bind(c) use, intrinsic :: iso_c_binding, only : c_float real(c_float), allocatable :: x(:,:,:) end subroutine allocating_sub end interface 

我们注意到这样的Fortran接口与C函数原型兼容,该函数原型具有forms参数作为CFI_cdesc_t的指针。

将此C函数定义为(使用幻数,并缺少许多其他合理的检查等):

 #include "ISO_Fortran_binding.h" void allocating_sub(CFI_cdesc_t* x) { if (x->base_addr) CFI_deallocate(x); CFI_index_t lower[3]={-1, 5, 1}; CFI_index_t upper[3]={20, 9, 5}; CFI_allocate(x, lower, upper, 0); } 

CFI_index_t是“标准有符号整数类型的typedef名称,能够表示减去两个指针的结果”。

分配发生在CFI_allocate函数中,该函数在此处使用明显变量给出的下限和上限来分配x 。 在我们的例子中忽略了最终的数字( 0 ), x不对应于Fortran字符类型。

要完成该示例,请参加Fortran程序:

  use, intrinsic :: iso_c_binding, only : c_float implicit none interface subroutine allocating_sub(x) bind(c) import c_float real(c_float), allocatable :: x(:,:,:) end subroutine allocating_sub end interface integer i real(c_float), allocatable :: x(:,:,:) allocate(x(6,2,5)) print 1, (LBOUND(x,i), UBOUND(x,i), i=1,3) call allocating_sub(x) if (allocated(x)) print 1, (LBOUND(x,i), UBOUND(x,i), i=1,3) 1 format ("x has been allocated like x(",2(I0,":",I0,","),I0,":",I0,").") end 

该示例有点非最小,因为它还显示了CFI_deallocate函数以及尽管我们在C端有这个额外级别的事实,我们仍然可以通过组件x->base_addr访问该C函数中的内存。 如果没有分配Fortran变量,这是一个空指针; 否则它是Fortran数组的第一个元素的C地址,只要至少有一个元素。

可以在TS文档或即将发布的Fortran标准草案中找到更多细节。

ALLOCATABLE自从F90以来一直在Fortran,因此相当“古老”(在25岁以上并不是很流行)。

但是,出于好奇,为什么在c端需要内存分配? 如果你需要在F侧的那个数组,它将需要在某一点被分配或以其他方式在F侧声明一些空间。

此外,您可能实际上不需要Allocatable。 您可能会发现自动arrays更方便。 例如:

 Subroutine sr(ArrayA, Answer, iJunk) Real(4), Intent(In) :: ArrayA(:,:) ! immediately has correct dims etc Integer, Intent(In) :: iJunk Real(4), Intent(Out) :: Answer ! ! locals ! Real(4) :: ArrayB(Size(ArrayA, Dim = 1)) ! AUTOMATIC array declared "on the fly" with order of that of the leading dimension of ArrayA, for example. Real(4) :: ArrayC(iJunk) ! another way to create "dynamic" arrays ! ! ... do stuff End Subroutine sr ! All automatic (and allocatables) are cleared/destroyed "automatically" since F95, with F90 you should manually DeAllocate allocated arrays. 

这可以在你的c调用之前或之后完成,所以如果c返回所需的调光,你可以“自动”,或者分配为套装。

不确定这是否有帮助,因为我不确定我是否已经掌握了你的目标的本质。

另外,只是值得思考,而ISO绑定通常是一个好主意,它可能会引起一些头痛。 例如,在许多情况下(使用ISO),您必须将字符串作为单个char数组传递,比如使用n个字符的单个字符串。 这可能有点悲伤,特别是如果你有一个字符串数组等。混合语言位可以在没有ISO的情况下完成,在某些情况下可以少得多的“成本”。