如何将 C_FLOAT 数组传递给 Fortran 子例程

Posted

技术标签:

【中文标题】如何将 C_FLOAT 数组传递给 Fortran 子例程【英文标题】:How to pass an array of C_FLOAT to a Fortran subroutine 【发布时间】:2018-01-15 20:17:18 【问题描述】:

在 Fortran 中,我有一个 C_FLOAT 数组,它被声明为输入参数:

SUBROUTINE Main(n,myCArray)  BIND(C, NAME = 'Main')
INTEGER(C_INT),         INTENT(IN   ) :: n
REAL(C_FLOAT),          INTENT(INOUT), dimension(n) :: myCArray
    CALL PrintTheArray(n,myCArray)
END SUBROUTINE MAIN

正如Main子程序主体中所写,我想将myCArray传递给另一个子程序,如下所示:

SUBROUTINE PrintTheArray(n,theCArray)
INTEGER(C_INT),         INTENT(IN   ) :: n
REAL(C_FLOAT),          INTENT(INOUT), dimension(n) :: theCArray
print *, theCArray(1), theCArray(2)
END SUBROUTINE PrintTheArray

通过这样做,我从不打印数组的正确值。但是,如果我打印子程序Main() 中的值,则这些值是正确的。出了什么问题,我该如何解决?


在 Fortran 中传递 C_FLOAT 数组确实没有问题。所以这个问题是错误的。我在这里提供了一个最小、完整和可验证的示例(我使用 Ubuntu、GNU Fortran (GCC) 6.3.0、gcc (GCC) 6.3.0):

文件名为FORTRANFunc.f90的Fortran代码

MODULE TEST
USE, INTRINSIC :: ISO_C_Binding
  IMPLICIT NONE
contains
subroutine CALLFORTRAN(n,myArray) BIND (C, NAME = 'CALLFORTRAN')
  INTEGER(C_INT),  INTENT(IN   )  :: n
  REAL(C_FLOAT),   INTENT(IN   )  :: myArray(n)
  CALL PRINTARRAY(n,myArray)
end subroutine CALLFORTRAN

subroutine PRINTARRAY(n, myArray)
  INTEGER(C_INT),  INTENT(IN   )  :: n
  REAL(C_FLOAT),   INTENT(IN   )  :: myArray(n)
  print *, myArray(1), myArray(2)
end subroutine PRINTARRAY
END MODULE TEST

文件名为main.c的C代码

#include <stdio.h>
#include <stdlib.h>
extern void CALLFORTRAN(int* n, float* myArray);

int main()

   int n=2;
   float*  myArray = (float*) malloc(2);
   myArray[0] = 0.5;
   myArray[1] = 1.5;
   CALLFORTRAN(&n,myArray);
   return 0;

你可以编译:

gfortran -c FORTRANFunc.f90
gfortran main.c FORTRANFunc.o -o test

然后你执行:

./test

结果应该是:

  0.500000000       1.50000000

【问题讨论】:

你能为我们创建一个minimal reproducible example 吗? 确实,当它没有打印正确的值时,它会打印什么? Main() 中的值是否正确?需要详细的问题说明和minimal reproducible example。 我感觉问题出在 C 代码上。通常,在 Fortran 子例程之间传递 C_FLOAT 数组是没有问题的。 第二行通常是USE ISO_C_BINDING。 C 是按引用传递还是按值传递? @Holmz 如果上面的某个模块已经使用了use iso_c_binding,那么它绝对没有理由。 use iso_c_binding 不会以任何方式更改调用约定(按值/引用传递)。 【参考方案1】:

我无法重现 gfortran 5.4.0(完整版:GNU Fortran (Ubuntu/IBM 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609)或 IBM XL Fortran 的问题。可能是较新的 gfortran 有问题吗?

$ gfortran -c FORTRANFunc.f90
$ gcc -c main.c
$ gfortran FORTRANFunc.o main.o -o test
$ ./test
  0.500000000       1.50000000
$

另外,将dimension(n) 更改为dimension(*) 有什么不同吗?

【讨论】:

其实这个问题是错误的,正如上面澄清的那样。所以在 FORTRAN 中传递 C_FLOAT 数组是完全可以的。把 dimension(n) 改成 dimension(*) 也是对的。

以上是关于如何将 C_FLOAT 数组传递给 Fortran 子例程的主要内容,如果未能解决你的问题,请参考以下文章

Python ctypes:如何将 ctypes 数组传递给 DLL?

将 C++ 字符数组传递给 Fortran

将 C++ 字符数组传递给 Fortran

试图将一个连续的动态二维数组从 C 传递到 Fortran

试图将一个连续的动态二维数组从 C 传递到 Fortran

如何创建接口以将 c 字符数组转换为 fortran