我有一个现有的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
};
}
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
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
我使用以下命令编译它:
icc -c init.c
ifort -c init_mod.f90
ifort main.f90 init_mod.o init.o
在运行时,我会得到一个分段错误,因为据我所知,INIT_CP
没有指向任何信息。我知道我没有成功地让INIT_CP
指向我的C函数中的数组。所以我想弄清楚该怎么做。
如果有人对如何在Fortran中本地初始化这个数组有建议的话,我想知道。我要做的最后一个选择是在程序集中对这个数组进行一个小的初始化,并编写一个脚本来生成程序集代码来自己初始化这个数组(基于从小的初始化中获得的程序集,我可以对任意大小的数组模仿相同的内容)。我对此并不兴奋,但这可能是最简单、最可靠的解决方案。
最重要的是,我希望使用此数组的其他Fortran子程序能够看到它的形状和值都是静态的,这样就可以进行适当的过程间优化。
发布于 2015-11-20 19:48:53
Fortran可互操作变量必须具有外部链接.正如注释中其他人所建议的那样,将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的一次性时间之外,我希望您不会损失太多的性能。
https://stackoverflow.com/questions/33832026
复制相似问题