2016-01-22 259 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_;