【问题标题】:Subroutine C++ called from Fortran : How to deal with Dynamic memory allocation?从 Fortran 调用的子程序 C++:如何处理动态内存分配?
【发布时间】:2014-05-07 11:30:20
【问题描述】:

我目前有一个 C++ 程序,它执行一些任务(这里不重要)并将一些数据存储到一个动态分配的二维数组中(使用 C 函数 malloc)。它运行良好,我现在需要在 fortran 程序中访问这些数据。我目前正在 Fortran 中创建一个程序,它调用 C/C++ 中的子例程来执行我想要的任务,但是当 2D 动态数组充满数据时,我需要在返回 Fortran 主程序时访问它。 问题是我无法将数据返回到 Fortran 主程序(在 2D 可分配数组中) 我尝试编写一个简单的程序来传递在 C 子程序中分配的动态数组,该子程序由我的主 Fortran 程序调用,以便查看当我退出 C 子程序时是否可以访问数据。

这是我的小代码:

Fortran 主程序:

PROGRAM FORT_C

use iso_c_binding
IMPLICIT NONE

interface
    subroutine call_fc(pX,s) bind(C,name='call_fc_')
        import
        integer(c_int)              :: s
        type(c_ptr), allocatable    :: pX
    end subroutine
end interface

integer(c_int)                              :: i
integer(c_int), pointer                     :: X(:)
type(C_ptr), allocatable                    :: pX


call call_fc(pX,100)
call c_f_pointer(pX,X,[100])

END

C 子程序:

#include <cstdlib>
#include <iostream>

using namespace std;

extern "C" 
{
    void call_fc_(int **x, int s);
    void c_func_deallocate(int **x);
}


void call_fc_(int **x, int s)
{
    int i;
    *x = (int *) malloc(sizeof(int)*s);
    for(i=0;i<100;i++)
    {
        cout << i << endl;
        *x[i]=i;
    }
}

void c_func_deallocate(int **x)
{
    free(*x);
}

这真的很简单,但我得到了这个输出:

0
1
forrtl: severe (174): SIGSEGV, segmentation fault occurred
Image              PC                Routine            Line        Source             
exemple            000000000040304C  Unknown               Unknown  Unknown
exemple            0000000000402F25  Unknown               Unknown  Unknown
exemple            0000000000402ECC  Unknown               Unknown  Unknown
libc.so.6          000000331241ECDD  Unknown               Unknown  Unknown
exemple            0000000000402DC9  Unknown               Unknown  Unknown

我不明白为什么我在 i>1 时得到这个 我希望我清楚我的问题,有人可以帮忙吗?

非常感谢!

【问题讨论】:

    标签: c++ arrays memory-management fortran


    【解决方案1】:

    您的问题是*x[i]=i; 表示*(x[i])=i;,但您想要的是(*x)[i]=i;

    发生这种情况是因为x[i]*x 都是指向int 的指针,因此编译器无法捕获错误。
    *x[i] 等价于x[i][0],而(*x)[i] 等价于x[0][i]。)

    为了避免问题和括号,您可以这样重写:

    void call_fc_(int **x, int s)
    {
        int i;
        int *y = (int *) malloc(sizeof(int)*s);
        for(i = 0; i < 100 && i < s; i++)
        {
            cout << i << endl;
            y[i]=i;
        }
        *x = y;
    }
    

    我为i &lt; s 添加了一个测试,以避免写入数组之外。

    【讨论】:

    • 非常感谢,实际上段错误不再出现,这很棘手!但是我现在有另一个问题,似乎我可以访问比使用 malloc 分配更多的内存。我展示了整个代码(很小),因为我还执行了一些更改(例如,用 *s 代替 s)和输出。
    • Fortran: PROGRAM FORT_C 使用 iso_c_binding IMPLICIT NONE 接口子程序 call_fc(pX,s) bind(C,name='call_fc_') import integer(c_int) :: s type (c_ptr), allocatable :: pX end subroutine end interface integer(c_int) :: i integer(c_int) :: s integer(c_int), pointer :: X(:) type(C_ptr), allocatable :: pX s=100 call call_fc(pX,s) call c_f_pointer(pX,X,(/s/)) END
    • C 子程序: #include #include using namespace std; extern "C" { void call_fc_(int x, int *s);无效 c_func_deallocate(int **x); } void call_fc_(int **x, int *s) { int *y = (int *) malloc(sizeof(int)*(*s)); for(int i=0; i 0 1 2 3 4 5 6 7 8 9
    • 我想在尝试访问分配的空间时出现段错误,但似乎没有打扰它...为什么会这样?再次感谢您的回答,非常有帮助!
    • 对于 cmets 的形状很抱歉,我无法以普通用户的身份在接下来的 8 小时内发布答案...
    【解决方案2】:

    除其他外,您在 Fortran 中的 C++ 函数接口声明 pX 参数是可分配的。请注意,对此的支持需要一个支持未来 F201X 标准的该功能的编译器。这样的人不多。

    我非常怀疑这不是您想要的 - 但如果您这样做了,C++ 参数声明与您所拥有的完全不同。有关更多信息,请参阅 TS 以了解与 C 的进一步互操作性。

    您不需要也不希望 pX 是可分配的,无论是作为主程序中的变量还是参数。您不是在“分配” pX - 它是一个 C_PTR,您要使用 C++ 函数分配的某些内存的 C 地址来定义它。

    另外,接口中的s 参数声明时没有VALUE 属性。这意味着它对应于 C 端的指针参数。您的 C 定义显示它是按值传递的。

    【讨论】:

    • 感谢您回答 IanH,关于 s 参数,我更正了它(如前面的 cmets 所述)。关于pX,我把“allocatable”改成了“pointer”(在之前的评论中也提到过,对不起cmets里面的代码结构,我别无选择)。我真的是混合两种语言的新手,所以如果我写了一些愚蠢的东西,我深表歉意!我打算在 Fortran 中声明的是一种指针,用于访问在 C 子例程中分配的数组。你知道如何做到这一点吗?
    • Fortran 中与 C 中的指针相同的“一种指针”只是一个 C_PTR - 您不希望接口主体中的虚拟参数上的 POINTER 属性。 Fortran 指针在某些方面与 C 指针“不同”——这就是为什么您使用 C_F_POINTER 将 Fortran 中的 C 指针转换为 Fortran 指针的原因。
    • 我删除了 POINTER 属性,现在它可以正常工作了。我开始了解在混合 Fortran 和 C 时如何处理动态内存。谢谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 2019-09-13
    • 2017-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-06
    相关资源
    最近更新 更多