gpt4 book ai didi

c++ - 使用 Fortran 中的内存数据调用 C 代码

转载 作者:太空狗 更新时间:2023-10-29 20:03:53 24 4
gpt4 key购买 nike

我有一个复杂的 C++ 对象,我想在我的 Fortran 代码中使用它。一般情况下,从Fortran调用C++代码是没有问题的(只需要提供一个合适的接口(interface),比如C linkage)。

但是我的问题是,我希望对 C++ 的 Fortran 调用对我称之为持久对象的对象进行操作:由第一个 init 函数创建并由其他 C++ 函数操作的 C++ 对象。

更具体地说,假设我有以下 C++ 代码

struct A {
public:
void do() { // do something on complicated stuff
private:
... // complicated stuff
};

extern "C" {
void* init_A() {
A* a = new A();
return reinterpret_cast<void*>(a);
}

void doSth(void* ptr_to_A) {
A* a = reinterpret_cast<A*>(ptr_to_A);
a.do();
}

void teardown_A(void* ptr_to_A) {
A* a = reinterpret_cast<A*>(ptr_to_A);
delete a;
}
}

以及以下 Fortran 代码(假设它是 main() ):

USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_PTR
INTERFACE
TYPE(C_PTR) FUNCTION init_A() BIND(C, NAME='init_A')
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_PTR
IMPLICIT NONE
END FUNCTION init_A

SUBROUTINE doSth(ptr_to_A) BIND(C, NAME='doSth')
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_PTR
IMPLICIT NONE
TYPE(C_PTR), INTENT(IN), VALUE :: ptr_to_A
END SUBROUTINE doSth

SUBROUTINE teardown_A(ptr_to_A) BIND(C, NAME='teardown_A')
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_PTR
IMPLICIT NONE
TYPE(C_PTR), INTENT(IN), VALUE :: ptr_to_A
END SUBROUTINE teardown_A
END INTERFACE

现在在我的真实代码中,它可以编译、链接,有时可以,但有时不能:似乎 Fortran 代码不保证在 init_A() 中分配的内存保持不变)

我无法在 Internet 上找到任何相关信息:

  • 您知道是否有任何标准机制可以确保由 init_A_() 分配的内存保持不变并且仍然由 fortran 代码分配?
  • 您是否知道适合我的问题的任何其他机制?

此外,有人能解释一下为什么内存管理不正确吗?直到现在,我还以为

  • Fortran 会向操作系统请求内存,C++ 也是,

  • 操作系统给 Fortan 和 C++ 的内存段是不相关的,并且保证不重叠,

  • 如果要求新内存,操作系统不会让 Fortran 使用 C++ 内存,直到 C++ 释放它

  • 通过调用 teardown_A() 或在程序(即 Fortran main)终止时释放 C++ 内存

编辑: 我用 IanH 的答案更新了我的代码,但这仍然不起作用(段错误,从 Fortran 调用 doSth() 时部分内存被释放

我发布的原始代码如下(评论引用)

struct A {
public:
void do() { // do something on complicated stuff
private:
... // complicated stuff
};

extern "C" {
void init_A_(long* ptr_to_A) { // ptr_to_A is an output parameter
A* a = new A();
*ptr_to_A = reinterpret_cast<long>(a);
}

void doSth_(long* ptr_to_A) {
A* a = reinterpret_cast<A*>(*ptr_to_A);
a.do();
}

void teardown_A_(long* ptr_to_A) {
A* a = reinterpret_cast<A*>(*ptr_to_A);
delete a;
}
}

和 Fortran 代码:

integer :: ptr_to_A

call init_A(ptr_to_A)

do i=1,10000
call doSth(ptr_to_A)
enddo

call teardown_A(ptr_to_A)

最佳答案

Fortran 2003 在 Fortran 语言中引入了 C 互操作性。这种语言特性使得编写可以以可移植和健壮的方式协同工作的 Fortran 和 C(以及 C++)源代码变得更加容易。除非出于其他原因无法使用此级别的语言,否则您应该非常使用此功能。

您有一个指针间接问题 - 指向 C++ 对象的指针是存储在 long 还是指向 long 的指针中(doSth_ 和 teardown_A_ 中强制转换的操作数前面应该有一个 *)。这取决于您使用的 C++ 和 Fortran 编译器,但 C long、C 指针和 Fortran 默认类型整数之间的大小可能不匹配。

下面的修改示例显示了使用 Fortran 2003 的 C 互操作性功能的方法。

// C++
struct A {
public:
void do_something()
{
// ...
}
private:
// ...
};

// Note no need for trailing underscore.
extern "C" {
// Note pointer to pointer to void.
void init_A(void** ptr_ptr_to_A) {
A* a = new A;
*ptr_ptr_to_A = reinterpret_cast<void*>(a);
}

void doSth(void* ptr_to_A) {
A* a = reinterpret_cast<A*>(ptr_to_A);
a->do_something();
}

void teardown_A(void* ptr_to_A) {
A* a = reinterpret_cast<A*>(ptr_to_A);
delete a;
}
}


! Fortran 2003
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_PTR
IMPLICIT NONE
INTERFACE
SUBROUTINE init_A(ptr_to_A) BIND(C, NAME='init_A')
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_PTR
IMPLICIT NONE
! This argument is a pointer passed by reference.
TYPE(C_PTR), INTENT(OUT) :: ptr_to_A
END SUBROUTINE init_A
SUBROUTINE doSth(ptr_to_A) BIND(C, NAME='doSth')
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_PTR
IMPLICIT NONE
! This argument is a pointer passed by value.
TYPE(C_PTR), INTENT(IN), VALUE :: ptr_to_A
END SUBROUTINE doSth
SUBROUTINE teardown_A(ptr_to_A) BIND(C, NAME='teardown_A')
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_PTR
IMPLICIT NONE
! This argument is a pointer passed by value.
TYPE(C_PTR), INTENT(IN), VALUE :: ptr_to_A
END SUBROUTINE teardown_A
END INTERFACE
TYPE(C_PTR) :: ptr_to_A
INTEGER :: i
!****
CALL init_A(ptr_to_A)
DO i = 1, 100
CALL doSth(ptr_to_A)
END DO
CALL teardown_A(ptr_to_A)
END

关于c++ - 使用 Fortran 中的内存数据调用 C 代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24643090/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com