我们正在尝试接管C中遗留的Fortran代码(100,000行代码)的内存分配,因为我们正在使用C库在集群上分区和分配分布式内存.可分配变量在模块中定义.当我们调用使用这些模块的子例程时,索引似乎是错误的(移位了一个).但是,如果将相同的参数传递给另一个子例程,则会得到期望的结果.以下简单示例说明了该问题:
hello.f95:
MODULE MYMOD
IMPLICIT NONE
INTEGER, ALLOCATABLE, DIMENSION(:) :: A
SAVE
END MODULE
SUBROUTINE TEST(A)
IMPLICIT NONE
INTEGER A(*)
PRINT *,"A(1): ",A(1)
PRINT *,"A(2): ",A(2)
END
SUBROUTINE HELLO()
USE MYMOD
IMPLICIT NONE
PRINT *,"A(1): ",A(1)
PRINT *,"A(2): ",A(2)
CALL TEST(A)
end SUBROUTINE HELLO
main.cpp中
extern "C" int* __mymod_MOD_a; // Name depends on compiler
extern "C" void hello_(); // Name depends on compiler
int main(int args, char** argv)
{
__mymod_MOD_a = new int[10];
for(int i=0; i<10; ++i) __mymod_MOD_a[i] = i;
hello_();
return 0;
}
我们正在编译:
gfortran -c hello.f95; c++ -c main.cpp; c++ main.o hello.o -o main -lgfortran;
正在运行的./main的输出是
A(1): 1
A(2): 2
A(1): 0
A(2): 1
如您所见,尽管两个子例程都打印了A(1)和A(2),但A的输出却不同.因此,似乎HELLO从A(0)开始,而不是A(1).这可能是由于从未在Fortran中直接调用过ALLOCATE,所以它不知道A的范围.有什么解决方法吗?
解决方法:
Fortran数组伪参数始终从子例程中定义的下限开始.在通话期间不会保留其下限.因此,TEST()中的参数A将始终从1开始.如果希望从42开始,则必须执行以下操作:
INTEGER A(42:*)
关于分配,您在玩火.为此,最好使用Fortran指针.
integer, pointer :: A(:)
然后,您可以将数组设置为指向C缓冲区,方法是
use iso_c_binding
call c_f_pointer(c_ptr, a, [the dimensions of the array])
其中c_ptr的类型为(c_ptr),可与void *互操作,后者也来自iso_c_binding.
– -编辑 – –
一旦看到@Max la Cour Christensen实现了我上面概述的内容,我就会误解您的代码输出.描述符确实是错误的,尽管我没有写任何明显的错误.上面的解决方案仍然适用.