Don*_*nna 5 fortran pointers gfortran fortran-iso-c-binding intel-fortran
以下代码可在 GNU gfortran 和 Intel ifort 中编译。但只有gfortran编译版本才能成功运行。
program fort_tst
use iso_c_binding
INTEGER, POINTER :: a(:)
TYPE(C_PTR) :: ptr
INTEGER, POINTER :: b(:)
ALLOCATE(a(5))
ptr = c_loc(a)
CALL c_f_pointer(ptr,b,[5])
DEALLOCATE(b)
end program fort_tst
Run Code Online (Sandbox Code Playgroud)
英特尔编译代码中的错误是:
forrtl: severe (173): A pointer passed to DEALLOCATE points to an object that cannot be deallocated
Image PC Routine Line Source
fort_tst 000000000040C5A1 Unknown Unknown Unknown
fort_tst 0000000000403A17 Unknown Unknown Unknown
fort_tst 0000000000403812 Unknown Unknown Unknown
libc-2.17.so 00002AAAAB20F555 __libc_start_main Unknown Unknown
fort_tst 0000000000403729 Unknown Unknown Unknown
Run Code Online (Sandbox Code Playgroud)
gfortran 代码运行完成。快速 valgrind 检查没有发现任何泄漏。
有人可以确认上面的代码是否有效/合法吗?
我在跑步
ifort (IFORT) 2021.2.0 20210228
Run Code Online (Sandbox Code Playgroud)
和
GNU Fortran (GCC) 9.2.0
Copyright (C) 2019 Free Software Foundation, Inc.
Run Code Online (Sandbox Code Playgroud)
更新 :
有趣的是,gfortran 做了正确的事情(即仅释放已分配的内存),即使用户试图将其与不正确的索引重新映射或虚假的形状参数混淆。因此内部数组描述符被 gfortran 的 c_f_pointer 正确复制。
上面的帖子启发了以下解决方案。这个想法是创建一个包装实际数据数组的类型。然后,c_loc/c_f_pointer 序列可以与指向标量对象的指针一起正常工作。可以安全地分配存储在类型中的数据数组以及数组类型本身。
MODULE arraytype_m
TYPE, PUBLIC :: arraytype
INTEGER, ALLOCATABLE :: data(:)
END TYPE arraytype
END MODULE arraytype_m
PROGRAM fort_tst
USE iso_c_binding
USE arraytype_m
TYPE(arraytype), POINTER :: a, b
TYPE(C_PTR) :: ptr
ALLOCATE(a)
ALLOCATE(a%data(5))
!! Set to C-style pointer, and then copy back to Fortran pointer.
ptr = c_loc(a)
CALL c_f_pointer(ptr,b)
DEALLOCATE(b%data)
DEALLOCATE(b)
END PROGRAM fort_tst
Run Code Online (Sandbox Code Playgroud)
这适用于英特尔和 gfortan,并且确实是比我尝试做的更好的解决方案。
特别感谢 @Federico 发布 C++/Fortran 代码,使这个解决方案变得显而易见。
更新:完整的代码,展示了如何ptr将上述内容存储在 C 中。
// C code
typedef void* arraytype;
void allocate_array(arraytype *ptr);
void deallocate_array(arraytype *ptr);
void do_something(arraytype *ptr);
int main()
{
arraytype ptr;
allocate_array(&ptr);
do_something(&ptr);
deallocate_array(&ptr);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
以及相应的 Fortran :
!! Fortran code
MODULE arraytype_mod
TYPE, PUBLIC :: arraytype
DOUBLE PRECISION, POINTER :: data(:)
END TYPE arraytype
END MODULE arraytype_mod
SUBROUTINE allocate_array(ptr) BIND(C,name='allocate_array')
USE iso_c_binding
USE arraytype_mod
TYPE(c_ptr) :: ptr
TYPE(arraytype), POINTER :: a
ALLOCATE(a)
ALLOCATE(a%data(5))
ptr = c_loc(a)
END
SUBROUTINE deallocate_array(ptr) BIND(C,name='deallocate_array')
USE iso_c_binding
USE arraytype_mod
TYPE(C_PTR) :: ptr
TYPE(arraytype), pointer :: a
CALL c_f_pointer(ptr,a)
DEALLOCATE(a%data)
DEALLOCATE(a)
END
SUBROUTINE do_something(ptr) BIND(C,name='do_something')
USE iso_c_binding
USE arraytype_mod
TYPE(c_ptr) :: ptr
TYPE(arraytype), POINTER :: a
CALL c_f_pointer(ptr,a)
a%data = 2.5
WRITE(6,*) a%data
END
Run Code Online (Sandbox Code Playgroud)