将分配给Fortran数组的C_PTR传递给C

将分配给Fortran数组的C_PTR传递给C,c,fortran,fortran-iso-c-binding,C,Fortran,Fortran Iso C Binding,我在访问C中的数组时遇到了SEGFULTS问题,该数组在下面的Fortran文件中分配。这里有一些调试的人工制品,例如文件写入没有写入任何有意义的内容,我初始化了一个从未使用过的变量I 然而,我发现了以下几点: 未初始化i(但仍声明):无segfault 未在C中打开文件:无segfault 未在代码中的其他位置打印HESS(不打印HESS)(不打印HESS_COPY):无SEGSFAULT 使用不同的名称声明和初始化i:segfault 有人知道是什么导致了这种行为吗?SEGFULT本身发

我在访问C中的数组时遇到了SEGFULTS问题,该数组在下面的Fortran文件中分配。这里有一些调试的人工制品,例如文件写入没有写入任何有意义的内容,我初始化了一个从未使用过的变量
I

然而,我发现了以下几点:

  • 未初始化
    i
    (但仍声明):无segfault
  • 未在C中打开文件:无segfault
  • 未在代码中的其他位置打印HESS(不打印HESS)(不打印HESS_COPY):无SEGSFAULT
  • 使用不同的名称声明和初始化
    i
    :segfault
有人知道是什么导致了这种行为吗?SEGFULT本身发生在线路
阵列\u PTR=C\u LOC(HESS\u COPY(1,1))
处。我正在使用带有调试标志(无优化)的
gfortran
gcc
进行编译

valgrind
表示存在无效写入(前两个文件是我在下面显示的):

C文件


变量
HESS\u COPY
是Fortran过程
GET\u POINTER\u IN_C
的一个本地的、未保存的、可分配的变量

因此,每当过程开始执行时,它总是未分配的。因此,在该过程的第一个可执行语句中测试其分配状态是多余的

因此,在过程执行结束时,未保存的局部变量也会自动释放。因此,程序末尾的C_LOC引用将获得即将停止存在的对象的地址

然后,C代码与不存在的对象的地址一起工作,程序失败

如果
HESS\u COPY
变量保存为本地变量或保存的模块变量,则它将在过程调用之间继续存在

(所有模块变量从Fortran 2008开始保存,以前的语言版本正式要求,如果模块未在活动范围内连续引用,则相关模块变量需要明确的特定保存。)

(顺便说一句,从Fortran 2003开始,该语言的规则还意味着分配的测试、分配语句和后续赋值可以简单地用单个语句替换
HESS\u 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]`)
}

好的,我只需要一个Fortran指针。它可以保持在本地,匿名目标将在C的监督下生活。绝对同意。我不喜欢与使用已保存的可分配项(或真正保存的任何内容)相关联的隐藏状态,但是使用指针会在Fortran端引入一个附带的释放例程。我想这可能会混淆答案中关于未保存的本地可分配变量行为的问题中的潜在误解。因此,当我不执行其他内存操作时,它是否(错误地)工作,因为它恰好在内存中保留了适当的值?另外,如何使用Fortran指针?我会为它分配空间,然后在C例程中进行内存释放吗?调用
free
如何知道要提供多少内存?实际上-您有两个问题-C端的指针间接指向不正确。下面是一些编辑。
#include <stdio.h>

void get_pointer(double ** hessian);

void print_hess(int *arr_size) {
   // Create a pointer to handle the hessian
   double **hessian;
   int i;
   i = 0;
   get_pointer(hessian);

   printf("%8.3f", **hessian);
   // Open a file for writing
   FILE *fptr = fopen("hessian_out", "w");  
   // Print the hessian
   fprintf(fptr, "\n");
   fclose(fptr);
}
MODULE MODSPARSEHESS
USE, INTRINSIC :: ISO_C_BINDING
USE MODHESS, ONLY: HESS

INTERFACE
   SUBROUTINE PRINT_HESSIAN(DIMENSIONS) BIND(C, NAME='print_hess')
      USE, INTRINSIC :: ISO_C_BINDING
      INTEGER(C_INT) :: DIMENSIONS
   END SUBROUTINE PRINT_HESSIAN
END INTERFACE

CONTAINS

   SUBROUTINE GET_POINTER_IN_C(ARRAY_PTR) BIND(C, NAME='get_pointer')
   !  C signature: void get_pointer(double ** hessian);
      USE, INTRINSIC :: ISO_C_BINDING
      IMPLICIT NONE

   ! Arguments
      TYPE(C_PTR), INTENT(OUT)            :: ARRAY_PTR
   ! Local variables
      REAL(C_DOUBLE), DIMENSION(:,:), &
      ALLOCATABLE, TARGET                 :: HESS_COPY

   ! Copy the hessian into HESS_COPY
      IF (.NOT. ALLOCATED(HESS_COPY)) THEN
        ALLOCATE(HESS_COPY(SIZE(HESS, 1), SIZE(HESS, 2)))
      END IF
      HESS_COPY(:, :) = HESS(:, :)

   ! Now get the pointer
      ARRAY_PTR = C_LOC(HESS_COPY(1, 1))

   END SUBROUTINE GET_POINTER_IN_C
END MODULE MODSPARSEHESS
#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]`)
}
   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