将字符串从Fortran传递到c ++

时间:2017-06-27 12:44:54

标签: c++ fortran

我遵循以下示例(http://fortranwiki.org/fortran/show/Fortran+and+Cpp+objects)以使C ++代码适应Fortran,首先我尝试学习Fortran并在Fortran和C ++之间建立连接。

我修改了代码,我希望将字符串从Fortran传递给C ++

#include <iostream>
#include <string>

using namespace std;
class CWLiDAR {
    string name;

public:
    CWLiDAR(string);
};


CWLiDAR::CWLiDAR(string name)
{
    this->name = name;
}


/*
*/

/* C wrapper interfaces to C++ routines */
#ifdef __cplusplus
extern "C" {
#endif
CWLiDAR* CWLiDAR__new(string name)
{
    return new CWLiDAR(name);
}
void CWLiDAR__delete(CWLiDAR* This)
{
    delete This;
}
#ifdef __cplusplus
}
#endif

Fortran包装器

module CWLiDAR_module
  use, intrinsic :: ISO_C_Binding!, only: C_int, C_ptr, C_NULL_ptr
  implicit none
  private
  type CWLiDAR_type
    private
    type(C_ptr) :: object = C_NULL_ptr
  end type CWLiDAR_type
  interface
    function C_CWLiDAR__new (name, name_len) result(this) bind(C, name = "CWLiDAR__new")
      import
      type(C_ptr) :: this
      character(name_len, kind=C_CHAR), intent(IN) :: name
      integer :: name_len
    end function C_CWLiDAR__new
    subroutine C_CWLiDAR__delete (this) bind(C, name = "CWLiDAR__delete")
      import
      type(C_ptr), value :: this
    end subroutine C_CWLiDAR__delete
  end interface
  interface new
    module procedure CWLiDAR__new
  end interface new
  interface delete
    module procedure CWLiDAR__delete
  end interface delete
  public :: new, delete, CWLiDAR_type
contains


! Fortran wrapper routines to interface C wrappers
  subroutine CWLiDAR__new(this, name, name_len)
    type(CWLiDAR_type), intent(out) :: this
    character(*) :: name
    integer :: name_len
    this%object = C_CWLiDAR__new(name, name_len)
  end subroutine CWLiDAR__new
  subroutine CWLiDAR__delete(this)
    type(CWLiDAR_type), intent(inout) :: this
    call C_CWLiDAR__delete(this%object)
    this%object = C_NULL_ptr
  end subroutine CWLiDAR__delete
end module CWLiDAR_module

主要

program main
  use cwlidar_module
  type(CWLiDAR_type) :: lidar
  call new(lidar, "Test", 4)

  call delete(lidar)
end program main

如何修改Fortran包装器以将字符串从Fortran传递到C ++?

2 个答案:

答案 0 :(得分:1)

首先,你不能在Fortran和C之间的接口上使用std::stringstd::string是一些C ++实现定义的对象,它没有保证内存布局以便与Fortran互操作。

您必须使用纯C字符串。因此,CVLiDAR__new()必须接受char*类型的参数,并且fortran接口必须将此参数声明为

character(kind = c_char) :: name(*)

Fortran包装程序必须使用一些Fortran character伪参数,然后将其内容复制到一个适当分配的character(kind = c_char)数组中,然后传递给C函数。

此时,您的C接口函数可能会继续将其转换为C ++ std::string。这种转换是可选的,因为C ++可以像C一样处理C字符串。但是,添加转换将允许其余代码更纯粹的C ++。

在Fortran端组装时,不要忘记正确终止带有零字符的C字符串!

这些参数转换确实是PITA,如果您需要从Fortran调用任意数量的接口函数,建议编写生成Fortran包装器的生成器脚本。可以在文件cdi-1.8.1/interfaces/f2003/bindGen.rb中的气候数据接口库(CDI,源代码可以在https://code.mpimet.mpg.de/projects/cdi/files找到)中找到此类脚本的示例,其输出也在同一版本中发布cdi-1.8.1/src/mo_cdi.f90下的焦油球。对于您的案例,此脚本可能完全过度,但对于CDI而言,它可以正常运行,其输出可能会激发/帮助您了解如何正确进行转换。

答案 1 :(得分:0)

您无法从Fortran传递C ++ string(实际上是std::string)。它与C或Fortran完全不兼容,它是一种内部C ++类型。您必须使用C包装器并传递C兼容的字符数组。