从 C++ 访问 Fortran 模块的变量
accessing variables of fortran module from c++
目前我正在做一个需要将 Fortran 代码集成到 C++ 的项目。在 fortran 模块中声明了许多变量和数组。当相应的 fortran 声明为 real*8 rmax 且模块名称为 common_area 时,我可以通过将 c 变量声明为 extern double common_area_mp_rmax_ 来从 c 访问整数、浮点数和双精度类型。但是,当我尝试对数组执行相同操作时出现错误。
假设fortran模块中的代码是:
真实* 8,可分配,维度(:,:,:) :: x
我创建了一个 c 双指针作为:
extern "C"
{
double* common_area_mp_x_;
}
现在当我编译整个项目时,它显示 "multiple definition of `variable_area_mp_x_'"。我正在使用 CMake 来编译整个项目。
有人可以阐明我做错了什么吗?我是 Fortran 的新手,我很难解决这个问题。感谢您的宝贵时间和帮助。
谢谢,
思维导图
Fortran 2003 在标准 Fortran 语言中引入了与 C 的互操作性。除非您有充分的相反理由,否则您应该使用此语言功能提供的工具。有关示例,请参阅本网站上的 fortran-iso-c-binding 标签。
根据当前的 Fortran 标准(以及下一个标准修订草案),Fortran 可分配模块变量不能与 C 变量互操作。
在实现上,Fortran编译器会使用一个描述符来存储可分配变量的分配状态。此描述符不仅仅是一个指向数据的指针 - 有关详细信息,请参阅编译器的用户和参考指南中的 "Handling Fortran Array Descriptors"。
在这种情况下共享信息的最佳方法取决于您要执行的操作。一种选择是为可分配数组提供 TARGET 属性,然后有一个单独的 TYPE(C_PTR) 变量,其绑定标签带有目标的 C 地址。数组的大小等方面需要单独沟通。
MODULE common_area
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_PTR, C_DOUBLE
IMPLICIT NONE
...
REAL(C_DOUBLE), ALLOCATABLE, TARGET :: x(:,:,:)
TYPE(C_PTR), BIND(C, NAME='x_ptr') :: x_ptr
CONTAINS
! Call before operating on x_ptr in C++
SUBROUTINE init
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_LOC
ALLOCATE(x(1,2,3))
x_ptr = C_LOC(x)
END SUBROUTINE init
~~~
// After init has been executed, this is a
// pointer to the value of the allocatable module variable
extern "C" double *x_ptr;
给定一个 C++ 文件 test.cpp 包含内容
extern "C" { double * foo; }
extern double bar;
double asdf;
使用 gnu 工具
g++ -Wall -c test.cpp; nm test.o
> 0000000000000000 B asdf
> 0000000000000008 B foo
即使用第一个选项实际上会引入一个具有该名称的新符号。
在这种情况下,正确的选择是
extern double * common_area_mp_x_;
目前我正在做一个需要将 Fortran 代码集成到 C++ 的项目。在 fortran 模块中声明了许多变量和数组。当相应的 fortran 声明为 real*8 rmax 且模块名称为 common_area 时,我可以通过将 c 变量声明为 extern double common_area_mp_rmax_ 来从 c 访问整数、浮点数和双精度类型。但是,当我尝试对数组执行相同操作时出现错误。
假设fortran模块中的代码是: 真实* 8,可分配,维度(:,:,:) :: x
我创建了一个 c 双指针作为:
extern "C"
{
double* common_area_mp_x_;
}
现在当我编译整个项目时,它显示 "multiple definition of `variable_area_mp_x_'"。我正在使用 CMake 来编译整个项目。 有人可以阐明我做错了什么吗?我是 Fortran 的新手,我很难解决这个问题。感谢您的宝贵时间和帮助。
谢谢, 思维导图
Fortran 2003 在标准 Fortran 语言中引入了与 C 的互操作性。除非您有充分的相反理由,否则您应该使用此语言功能提供的工具。有关示例,请参阅本网站上的 fortran-iso-c-binding 标签。
根据当前的 Fortran 标准(以及下一个标准修订草案),Fortran 可分配模块变量不能与 C 变量互操作。
在实现上,Fortran编译器会使用一个描述符来存储可分配变量的分配状态。此描述符不仅仅是一个指向数据的指针 - 有关详细信息,请参阅编译器的用户和参考指南中的 "Handling Fortran Array Descriptors"。
在这种情况下共享信息的最佳方法取决于您要执行的操作。一种选择是为可分配数组提供 TARGET 属性,然后有一个单独的 TYPE(C_PTR) 变量,其绑定标签带有目标的 C 地址。数组的大小等方面需要单独沟通。
MODULE common_area
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_PTR, C_DOUBLE
IMPLICIT NONE
...
REAL(C_DOUBLE), ALLOCATABLE, TARGET :: x(:,:,:)
TYPE(C_PTR), BIND(C, NAME='x_ptr') :: x_ptr
CONTAINS
! Call before operating on x_ptr in C++
SUBROUTINE init
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_LOC
ALLOCATE(x(1,2,3))
x_ptr = C_LOC(x)
END SUBROUTINE init
~~~
// After init has been executed, this is a
// pointer to the value of the allocatable module variable
extern "C" double *x_ptr;
给定一个 C++ 文件 test.cpp 包含内容
extern "C" { double * foo; }
extern double bar;
double asdf;
使用 gnu 工具
g++ -Wall -c test.cpp; nm test.o
> 0000000000000000 B asdf
> 0000000000000008 B foo
即使用第一个选项实际上会引入一个具有该名称的新符号。
在这种情况下,正确的选择是
extern double * common_area_mp_x_;