使用C指针跟踪Fortran模块数据成员



我们有一个旧的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的有效参数:指针参数必须是标量。

最新更新