gpt4 book ai didi

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

转载 作者:太空宇宙 更新时间:2023-11-04 01:02:17 25 4
gpt4 key购买 nike

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

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

很自然地,我切换到 C 并编写了一个函数来初始化一个数组,它在几秒钟内就可以毫无问题地编译。现在我正试图将两者正确地联系在一起。我在这里创建了一个小测试用例来简化事情。这是我正在处理的三个文件:

初始化.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
};
}

初始化模块.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

主.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

我使用以下命令编译它:

icc -c init.c
ifort -c init_mod.f90
ifort main.f90 init_mod.o init.o

我在运行时遇到段错误,因为据我所知,INIT_CP 没有指向任何内容。我知道我没有成功地让 INIT_CP 指向我的 C 函数中的数组。所以我想弄清楚如何做到这一点。

如果有人对如何在 Fortran 中本地初始化这个数组有什么建议,我想知道。我要做的最后一个选择是在程序集中对这个数组进行一个小的初始化,并编写一个脚本来生成汇编代码来自己初始化这个数组(基于小初始化的程序集,我可以模拟任何大小的相同事物大批)。我不太愿意那样做,但这可能是最简单、最可靠的解决方案。

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

最佳答案

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

请注意,起始前提 - 不可能仅从 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, ... ]

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

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

但是,您可能会遇到编译器复杂性限制,这会破坏后一种方法。

f_init_g 是由 C 初始化的变量时,您基本上依赖于工具集的跨语言和跨过程优化功能 - 如果这些功能存在,我不会对于这种情况,他们期望很高。如果您在运行时从文件中读取数组的值,我希望您不会损失太多性能,除了 IO 的一次性时间。

关于c - Fortran 和 C 混合编程(共享内存),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33832026/

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