2014-02-07 47 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

谢谢,那是做的。 –