将fortran子例程链接到c ++程序时出错

时间:2014-02-07 15:39:08

标签: c++ linker fortran90

我正在将程序从Fortran转换为C ++。但是,为了保持输入兼容性,我按照in this question的说明使用了子程序和Fortran的名单功能。由于这是一个遗留代码,我正在处理的名单有30多个变量更荒谬。一切正常,直到我收到错误时链接:

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抛出上述错误。我想也许符号不匹配所以我在两个目标文件上运行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 个答案:

答案 0 :(得分: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 ++错位名称。这样,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