用内存中的Fortran数据调用C代码
Calling C code with in-memory data from Fortran
我有一个复杂的c++对象,我想在我的Fortran代码中使用。一般来说,从Fortran调用c++代码是没有问题的(只需要提供一个合适的接口,例如C链接)。
然而,我这里的问题是,我希望我的Fortran对c++的调用操作一个我称之为持久对象的东西:一个由第一个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
现在在我的实际代码中,这编译,链接,有时工作,但有时不:在init_A()中分配的内存似乎不能保证Fortran代码保持不变)
我在网上找不到任何关于这个的信息:
- 你知道是否有任何标准机制来确保init_A_()分配的内存保持不变,仍然由fortran代码分配吗?
- 你知道有什么其他的机制可以解决我的问题吗?
也,有人能解释我为什么内存管理不正确吗?直到现在,我一直认为
Fortran会向OS请求内存,c++也是,
操作系统给Fortan和c++的内存段是不相关的,保证不重叠,
如果请求新的内存,操作系统不会让Fortran使用c++内存,直到c++释放它
c++内存通过调用teardown_A()或当程序(即Fortran main)终止
释放。
编辑:我用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 调用C++代码而没有错误
- 在链接的程序集文件中,我想从 c++ 调用代码访问变量.是否可以在不触发访问冲突的情况下执行此操作?
- 从 ASM 调用C++代码中标准库的链接
- 如何从C#调用C 代码及其调用的代码
- 使用带有 MEX 包装器的帮助程序 C 文件从 MATLAB 2016 调用C++代码时出现问题
- 从 Swift 调用C++代码比调用 C 代码更"expensive"还是更慢?
- 从x64中的C#调用C 代码,所有参数都会偏移一个
- 使用C#的结构调用C 代码
- Golang:在跨平台调用C++代码
- 从 C# 调用 C/C++ 代码
- 调用 C 代码的 Win32 应用程序
- 从C#.NET应用程序调用C/C 代码
- 如何使用JNA从Android调用C/C 代码
- 当在C#中的WPF应用程序中单击一个按钮时,如何调用C 代码
- 从 C# 调用C++代码而不创建 dll
- 通过嵌入式 Python 调用C++代码
- 当我从C#代码调用C++代码时,它是线程安全的吗
- 如何从Node.js调用C++代码
- 让非托管 C++ 代码调用调用 C# 代码的托管 C++ 代码
- 使用C++中的引用从C#调用C++代码时出错