变量HESS_COPY
是 Fortran 过程的本地、未保存、可分配变量GET_POINTER_IN_C
.
因此,每当过程开始执行时,它总是未分配的。因此,在该过程的第一个可执行语句中测试其分配状态是多余的。
因此,在过程执行结束时,未保存的局部变量将被自动释放。因此,在过程结束时的 C_LOC 引用获得了即将停止存在的对象的地址。
然后,C 代码使用不存在的对象的地址,并且程序失败。
If the HESS_COPY
变量保存在本地或保存的模块变量中,它将在过程调用之间继续存在。
(自 Fortran 2008 起,所有模块变量均已保存,如果未在活动范围中持续引用模块,则以前的语言修订版本正式要求对相关模块变量进行显式指定的 SAVE。)
(顺便说一句,从 Fortran 2003 开始,该语言的规则也意味着分配测试、分配语句和后续赋值可以简单地替换为单个语句HESS_COPY = HESS
.)
此外,在 C 代码中,正在尝试返回不存在的指针中的信息。在原始代码中,hessian 被声明为指向指向双重的指针的指针 - 请注意两个间接级别。如果没有某种初始化,第一级间接寻址将“随机”指向内存中,然后 Fortran 代码将尝试将其结果存储在该随机位置。
作为替代方案,请考虑:
#include <stdio.h>
void get_pointer(double ** hessian);
void print_hess(int *arr_size) {
// A pointer to double (one level of indirection).
double *hessian;
// Pass the address of that pointer.
get_pointer(&hessian);
// print the value of the double being pointed at.
printf("%8.3f\n", *hessian);
// print the value of the next double in the array
// (assuming that there is more than one).
printf("%8.3f\n", *(hessian+1));
// (or equivalently, `hessian[1]`)
}
Vladimir F 在注释中提到的 Fortran 指针方法需要两个 Fortran 过程 - 一个类似于分配 Fortran 指针并复制数据的过程,第二个则取消分配该指针。对分配过程的每次调用都需要与对释放过程的相应调用相匹配,并传递相同的指针。大致如下:
SUBROUTINE GET_POINTER(ARRAY_PTR) BIND(C, NAME='get_pointer')
! C signature: void get_pointer(double **);
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_LOC, C_PTR, C_DOUBLE
TYPE(C_PTR), INTENT(OUT) :: ARRAY_PTR
REAL(C_DOUBLE), POINTER :: HESS_COPY(:,:)
! See also the SOURCE= specifier.
ALLOCATE(HESS_COPY(SIZE(HESS,1), SIZE(HESS,2))
HESS_COPY = HESS
ARRAY_PTR = C_LOC(HESS_COPY)
END SUBROUTINE GET_POINTER
SUBROUTINE RELEASE_POINTER(ARRAY_PTR) BIND(C, NAME='release_pointer')
! C signature: void release_pointer(double*);
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_PTR, C_F_POINTER, C_DOUBLE
TYPE(C_PTR), INTENT(IN), VALUE :: ARRAY_PTR
REAL(C_DOUBLE), POINTER :: HESS_COPY(:,:)
CALL C_F_POINTER(ARRAY_PTR, HESS_COPY, SHAPE(HESS))
DEALLOCATE(HESS_COPY)
END SUBROUTINE RELEASE_POINTER