2016-01-22 191 views
2

目前我正在研究一个需要将fortran代码集成到C++的项目。在Fortran模块中声明了很多变量和数组。当相应的fortran声明为real * 8 rmax且模块的名称为common_area时,我可以通过将c变量声明为extern double common_area_mp_rmax_来访问c中的整型,浮点型和双精度类型。但是,当我尝试对数组做同样的操作时,我得到错误。从C++访问fortran模块的变量

假设FORTRAN模块中的代码是: 真实* 8,分配,尺寸(:,:我cretaed AC双指针,:) :: X

为:

extern "C" { double* common_area_mp_x_; }

现在当我编译整个项目时,它说“variable_area_mp_x_'的多重定义”。我正在使用CMake来编译整个项目。 有人可以解释我做错了什么吗?我是fortran的新手,我很难解决这个问题。我感谢你的时间和帮助。

感谢, 精神狂欢

+0

缺少'extern'? –

+0

实际上我没有用C语言声明extern。我只是编辑并减少这种困惑..谢谢.. – mindbender

+0

由于它只是一个基本变量(不是结构,函数或类),所以如果需要,也许可以在头文件中省略double * common_area_mp_x_',然后在引用该变量的C++文件中声明'extern double * common_area_mp_x_'。 –

回答

5

Fortran 2003的部分采用C的互操作性为标准的Fortran语言。除非您有充分的理由相反,否则您应该使用此语言功能提供的功能。有关示例,请参阅本网站上的标签。

根据当前的Fortran标准(以及下一个标准修订草案),Fortran可分配模块变量不能与C变量互操作。

在实现方面,Fortran编译器将使用描述符来存储allocatable变量的分配状态。这个描述符不仅仅是一个指向数据的指针 - 请参阅编译器用户和参考指南中的“处理Fortran数组描述符”以获取更多信息。

在这种情况下共享信息的最佳方法取决于您正在尝试做什么。一种选择是为可分配数组提供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; 
+0

根据我的测试,这个问题似乎不是在fortran方面,而是在'extern double * ptr'应该用在C++代码中时使用'extern“C”double * ptr'。 –

+0

@ J.J.Hakala从Fortran方面来说,BIND(C)关于可互操作的参数使问题消失。 OP的方法还存在其他潜在的问题。现在是2016年......对于没有为这类问题编写标准的符合性代码,很少有有效的借口。 – IanH

+0

好的,我现在更详细地阅读fortran-iso-c-binding wiki。 –

2

给定一个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_;