Fortran和C混合编程(共享内存)

Jim*_*mmy 1 c fortran fortran-iso-c-binding

我有一个我正在使用的Fortran代码库,它非常庞大.我不是Fortran程序员,所以我知道我在这里做的并不正确.

我正在尝试创建并初始化一个包含160万个整数的数组.我无法在Fortran中初始化(使用ifort或gfort),因为我要么有太多的行连续,要么行太长.

很自然地,我切换到C并编写了一个函数来初始化一个数组,它在几秒钟内编译就没有问题了.现在我正在尝试将两者正确地连接在一起.我在这里创建了一个小测试用例来简化操作.以下是我正在使用的三个文件:

INIT.C

void c_init_()
{
  static const int f_init_g[1600000] =
  {
    3263, 322, 3261, 60, 32249, 32244, 3229, 23408, 252407, 25326,
    25805, 25723, 25562, 25787, 4549, 32248, 32244, 32243, 253207, 21806,
    ---------------------------------------------------------------------
    25805, 25723, 25562, 25787, 4549, 32248, 32244, 32243, 253207, 21806
  };
}
Run Code Online (Sandbox Code Playgroud)

init_mod.f90

MODULE INIT_MOD

  USE, INTRINSIC :: ISO_C_BINDING
  IMPLICIT NONE
  SAVE

  TYPE :: INIT_TYPE
    INTEGER (C_INT), DIMENSION(1600000) :: INIT
  END TYPE INIT_TYPE
  TYPE (C_PTR), BIND(C,NAME="f_init_g") :: INIT_CP
  TYPE (INIT_TYPE), POINTER :: INIT_FP

END MODULE INIT_MOD
Run Code Online (Sandbox Code Playgroud)

main.f90时

  PROGRAM INIT

    USE INIT_MOD
    USE, INTRINSIC :: ISO_C_BINDING

    TYPE (INIT_TYPE) :: INIT_T
    CALL c_init()
    CALL C_F_POINTER(INIT_CP,INIT_FP)
    INIT_T = INIT_FP

  END PROGRAM INIT
Run Code Online (Sandbox Code Playgroud)

我使用以下命令编译它:

icc -c init.c
ifort -c init_mod.f90
ifort main.f90 init_mod.o init.o
Run Code Online (Sandbox Code Playgroud)

我在跑步时遇到了分段错误,因为INIT_CP据我所知,它没有任何结果.我知道我没有成功INIT_CP地指向我的C函数中的数组.所以我想弄清楚如何做到这一点.

我想如果有人建议如何在Fortran中本地初始化这个数组.我要做的最后一个选择是在程序集中对这个数组做一个小的初始化,并编写一个脚本来生成汇编代码来自己初始化这个数组(基于小的初始化程序集,我可以模仿任何大小的相同的东西)数组).我不是那么兴奋,但它可能是最简单,最可靠的解决方案.

最重要的是,我希望使用此数组的其他Fortran子例程看到它在形状和值上是静态的,以便可以进行适当的过程间优化.

Ian*_*anH 5

Fortran-C互操作变量必须具有外部链接.正如其他人在评论中所建议的那样,将C声明移到文件范围并丢失说明static符.

不需要中间C_PTR- Fortran数组变量可以与相应的C数组直接互操作.

稍微减小阵列的大小:

/* C File scope */
const int f_init_g[3] = { 101, 102, 103 };

! Fortran
MODULE m
  USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_INT
  IMPLICIT NONE
  INTEGER(C_INT), BIND(C, NAME='f_init_g') :: f_init_g(3)
END MODULE m

PROGRAM p
  USE m
  IMPLICIT NONE
  PRINT *, f_init_g(2)
END PROGRAM p
Run Code Online (Sandbox Code Playgroud)

请注意,起始前提 - 无法仅在Fortran中定义或初始化此类数组 - 是错误的.Fortran中常量表达式的规则允许引用现有的命名常量,包括作为数组的命名常量.如果您决定坚持这种疯狂,并假设初始化程序的值不能通过某种表达式来描述,请考虑:

INTEGER, PARAMETER :: first(10)  &
   = [ 3263,    322,     3261,    60,       32249,  &
       32244,   3229,    23408,   252407,   25326 ]
INTEGER, PARAMETER :: second(10)  &
   = [ 25805,   25723,   25562,   25787,    4549,  &
       32248,   32244,   32243,   253207,   21806]
...
INTEGER, PARAMETER :: f_init_g(1600000) = [ first, second, ... ]
Run Code Online (Sandbox Code Playgroud)

在最终的数组构造函数之前,您可能需要中间命名的常量数组.

在上面,f_init_g是一个命名常量,它对编译器非常可见,更有可能导致您寻求的优化.

但是,您可能遇到编译器复杂性限制,这会使后一种方法失败.

何时f_init_g是由C初始化的变量,您基本上依赖于工具集的语言间和程序间优化功能 - 如果这些功能甚至存在,那么对于这种情况我不会期望太多.如果你在运行时从文件中读取数组的值,我希望你不会在IO的一次性时间内失去很多性能.