gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-02 09:34:42 27 4
gpt4 key购买 nike

我在访问 C 数组时遇到段错误,该数组在下面的 Fortran 文件中分配。有一些调试问题,例如文件写入没有写入任何有意义的内容,并且我初始化了一个我从未使用过的变量 i

但是,我发现了以下内容:

  • 未初始化 i(但仍声明它):无段错误
  • 未在 C 中打开文件:无段错误
  • 不在代码中的其他位置打印 HESS(不是 HESS_COPY):无段错误
  • 使用不同的名称声明并初始化 i:segfault

有谁知道什么可能会导致这种行为?段错误本身发生在 ARRAY_PTR = C_LOC(HESS_COPY(1, 1)) 行。我正在使用带有调试标志的 gfortrangcc 进行编译(无优化)。

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

 Invalid write of size 8
at 0xBEEA3E: get_pointer (modsparsehess.f90:34)
by 0xA75D7A: print_hess (sparse_hessian_c.c:108)
by 0x866C95: quench_ (quench.f:316)
by 0x7F2DBE: mc_ (mc.F:368)
by 0x4B65E2: mcruns_ (mcruns.f:62)
by 0x459245: MAIN__ (main.F:430)
by 0x45A33F: main (main.F:21)
Address 0x87 is not stack'd, malloc'd or (recently) free'd

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);
}

Fortran 文件

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

最佳答案

变量HESS_COPY是Fortran过程GET_POINTER_IN_C的本地、未保存、可分配的变量。

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

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

然后,C 代码使用不存在的对象的地址,并且程序失败。

如果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

关于c - 将分配的 C_PTR 到 Fortran 数组传递给 C,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28351919/

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