2014-02-07 46 views
0

我正在將程序從Fortran轉換爲C++。但是,爲了保持輸入兼容性,我按照in this question的說明使用了子程序和Fortran的名單列表功能。由於這是一個遺留代碼,我正在使用的名稱列表比30多個變量更荒謬。一切正常,直到連接時出現錯誤:將fortran子程序鏈接到C++程序時出錯

main.cpp:(.text+0x2732): undefined reference to `readDatainMesh(double*, int*, int*, double*, char*, double*, char*, int*, int*, int*, double*, int*, int*, int*, double*, double*, double*, int*, int*, int*, int*, double*, double*, double*, double*, int*, int*, double*, int*, int*, double*, char*, double*, double*, double*, int*, double*, double*, double*, int*, int*, int*, char*, char*, double*, double*)' 

我有以下輸入文件:

readNamelists.f90:

subroutine readDatainMesh(...) & 
     bind(c, name='readDatainMesh') 
     use,intrinsic :: iso_c_binding,only:c_double,c_int,c_char 
     implicit none 

     real(kind=c_double), intent(inout) :: realVars 
     integer(kind=c_int), intent(inout) :: intVars 
     character(kind=c_char), intent(inout) :: charVars 
     . 
     . 
     .  

    namelist/datain_mesh/... 

     open(unit = 100, file = 'input.nam', status = 'old') 
     read(unit = 100, nml = datain_mesh) 
     close(unit = 100) 

endsubroutine readDatainMesh 

我與gfortran -Wall -o readNamelists.o -c readNamelists.f90編譯。這會產生關於未使用的虛擬變量的警告,但僅此而已。

我有一個函數的C頭,我已經檢查了main.cpp和fortran實現中的被調用函數。它看起來像:

#ifndef READNAMELISTS_H 
#define READNAMELISTS_H 

void readDatainMesh(...); 

#endif 

我打電話gcc -Wall -o main.o -c main.cpp它沒有任何警告。然後最後gcc -Wall -o main main.o readNamelists.o -lstdc++ -lgfortran其中引發上述錯誤。我想也許符號匹配的werent所以我跑了兩個目標文件和感興趣的線路nm是:

0000000000000000 T readDatainMesh 

   U _Z14readDatainMeshPdPiS0_S_PcS_S1_S0_S0_S0_S_S0_S0_S0_S_S_S_S0_S0_S0_S0_S_S_S_S_S0_S0_S_S0_S0_S_S1_S_S_S_S0_S_S_S_S0_S0_S0_S1_S1_S_S_ 

這顯然不匹配。我的問題是如何解決這個問題?

+1

你試過在函數聲明之前添加'extern「C」'?問題在於修改和不同的調用約定。 – AlexT

回答

2

_Z14readDatainMeshPdPiS0_S_PcS_S1_S0_S0_S0_S_S0_S0_S0_S_S_S_S0_S0_S0_S0_S_S_S_S_S0_S0_S_S0_S0_S_S1_S_S_S_S0_S_S_S_S0_S0_S0_S1_S1_S_S_是包含參數類型的C++ mangled名稱。通過這種方式,C++編譯器可以爲重載函數提供不同的符號並區分它們。

一個可以從命令行還原函數是:

$ echo _Z14readDatainMeshPdPiS0_S_PcS_S1_S0_S0_S0_S_S0_S0_S0_S_S_S_S0_S0_S0_S0_S_S_S_S_S0_S0_S_S0_S0_S_S1_S_S_S_S0_S_S_S_S0_S0_S0_S1_S1_S_S_ | demangle 
readDatainMesh(double*, int*, int*, double*, char*, double*, char*, int*, int*, int*, double*, int*, int*, int*, double*, double*, double*, int*, int*, int*, int*, double*, double*, double*, double*, int*, int*, double*, int*, int*, double*, char*, double*, double*, double*, int*, double*, double*, double*, int*, int*, int*, char*, char*, double*, double*) 

因此你必須告訴C++編譯器把這個作爲C函數沒有超載。這可以使用extern "C"完成。如果相同的標題是從C和C++代碼中使用還需要一個後衛,因爲extern "C"不完全在C.

有效的標題可能是這樣的:

#ifndef READNAMELISTS_H 
#define READNAMELISTS_H 

#ifdef __cplusplus 
extern "C" { 
#endif 
void readDatainMesh(...); 
#ifdef __cplusplus 
} 
#endif 

#endif 

如果您做C++只,這是你可以縮短它的唯一功能

#ifndef READNAMELISTS_H 
#define READNAMELISTS_H 

extern "C" void readDatainMesh(...); 

#endif 
+0

謝謝,那是做的。 –