我们有一个旧的fortran 90代码,该代码在一组数据阵列上运行,并希望范围代码,以便我们可以拥有几组数据。不幸的是,子例程都没有进行输入参数,而是通过模块进行评估的所有数据。以下代码类似于我们的fortran代码。
MODULE test_mod
IMPLICIT NONE
double precision, pointer :: f_x(:)
integer :: n = 5
END MODULE test_mod
SUBROUTINE alloc_x()
use test_mod
IMPLICIT NONE
allocate(f_x(n))
END SUBROUTINE alloc_x
SUBROUTINE init_x()
USE test_mod
IMPLICIT NONE
f_x = 1.0
END SUBROUTINE init_x
SUBROUTINE dealloc_x()
use test_mod
IMPLICIT NONE
deallocate(f_x)
END SUBROUTINE dealloc_x
由于fortran代码足够复杂(大约有一百个数组,都处于不同形状和尺寸(,因此代码的修改越少。我们已经提出了以下解决方案,并且对该解决方案是否与Fortran 90标准兼容:
很感兴趣:我们创建了两个额外的fortran子例程,它们存储分配的fortran数组的位置,并将c指针复制回模块。
SUBROUTINE store_ptrs(c_x)
use iso_c_binding
use test_mod
IMPLICIT NONE
TYPE(c_ptr) :: c_x
c_x = c_loc(f_x)
END SUBROUTINE
SUBROUTINE copy_ptrs2mod(c_x)
use iso_c_binding
use test_mod
IMPLICIT NONE
TYPE(c_ptr) :: c_x
CALL c_f_pointer(c_x,f_x,[n])
END SUBROUTINE
使用这两个子例程,我们可以拥有更多的数据副本(以下代码中的10个副本(,而无需更改fortran代码 -
#include <stdio.h>
#include <stdlib.h>
void alloc_x_();
void init_x_();
void dealloc_x_();
void store_ptrs_(double **c_x);
void copy_ptrs2mod_(double **c_x);
void output_result(int entry, double* array);
int main()
{
int i;
double *x[10];
/* allocate array */
for(i=0; i<10; i++){
alloc_x_();
store_ptrs_(&x[i]);
}
/* initialize array */
for(i=0; i<10; i++){
copy_ptrs2mod_(&x[i]);
init_x_();
output_result(i,x[i]);
}
/* deallocate the array */
for(i=0; i<10; i++){
copy_ptrs2mod_(&x[i]);
dealloc_x_();
}
}
void output_result(int entry, double* array){
int j;
printf("x[%2d] = [", entry);
for (j = 0; j < 5; ++j)
{
if (j == 4)
{
printf("%3.1f",array[j]);
continue;
}
printf("%3.1f, ",array[j]);
}
printf("]n");
}
输出 -
x[ 0] = [1.0, 1.0, 1.0, 1.0, 1.0]
x[ 1] = [1.0, 1.0, 1.0, 1.0, 1.0]
x[ 2] = [1.0, 1.0, 1.0, 1.0, 1.0]
x[ 3] = [1.0, 1.0, 1.0, 1.0, 1.0]
x[ 4] = [1.0, 1.0, 1.0, 1.0, 1.0]
x[ 5] = [1.0, 1.0, 1.0, 1.0, 1.0]
x[ 6] = [1.0, 1.0, 1.0, 1.0, 1.0]
x[ 7] = [1.0, 1.0, 1.0, 1.0, 1.0]
x[ 8] = [1.0, 1.0, 1.0, 1.0, 1.0]
x[ 9] = [1.0, 1.0, 1.0, 1.0, 1.0]
尽管我们尚未看到任何问题,但我们有些担心,我们可能会(隐含地(依靠编译器的特定实现各种标准的实现,或者其他与最近的标准的其他不相容性可能会阻止这一点。我们将非常感谢有关这种处理方法的任何评论或反馈,即遗产90代码必须是一个普遍的问题。
我不会说您的代码/方法是正确的,但我会确定一件事会引起我最初的关注。您可以简单地解决这个问题。
从您的名字杂乱无章的事实中,在C侧给出了原型
void alloc_x_();
void init_x_();
void dealloc_x_();
void store_ptrs_(double **c_x);
void copy_ptrs2mod_(double **c_x);
这表明Fortran过程在任何模块之外(在子例程语句中没有bind(c,name='alloc_x_')
等(。在Fortran 2008之前,有一个关于模块变量在活动范围中不再引用的模块变量的规则。
在您拥有的C执行中,引用了alloc_x
的CC_2。但是,一旦子例程完成,test_mod
就不再在任何活动范围中引用。在Fortran 90到Fortran 2003规则下,模块变量f_x
当时不确定。之后,在store_ptrs
中,c_loc(f_x)
中的参考是不合格的。
将save
属性添加到模块本地变量,或遵循Fortran 2008标准,解决此问题。
说,在Fortran 2003 C互操作性规则下,f_x
不是c_loc
的有效参数:指针参数必须是标量。