Fortran,ISO C BINDING和std :: string

时间:2015-03-08 01:38:02

标签: c++ fortran fortran-iso-c-binding

我有一个带签名的c ++方法

extern std::string os_dtoa_format(double  x);

我想从Fortran打来电话。我知道我必须构建一个显式接口,但我不确定如何去做。我对如何处理double有一个模糊的想法,但我还没有找到关于std :: string的任何信息。 char *似乎很难,这让我想问是否有可能做我想做的事。

1 个答案:

答案 0 :(得分:6)

有几种方法可以安排这个,下面只讨论一种可能性。除了在C ++函数周围提供外部“C”包装函数之外,您希望能够从Fortran调用此函数,此示例还使用从C ++调用的小型Fortran过程,以便实际复制std中的数据: :字符串结果到Fortran字符变量。 Fortran一侧的工作实物类型和字符类型之间的差异很可靠,分别与C_DOUBLE和C_CHAR不同。

C ++代码:

#include <string>

// The function returning a std::string that you wish to call from Fortran.
std::string os_dtoa_format(double x);
// Utility provided via Fortran code to copy a C string to a deferred length 
// allocatable component of an object nominated by the fstring_ptr pointer.
extern "C" void set_fortran_string(void* fstring_ptr, int length, const char* str);

// A wrapper for the Fortran code to call.
extern "C" void os_dtoa_format_wrapper(double x, void* fstring_ptr)
{
   std::string s = os_dtoa_format(x);
   set_fortran_string(fstring_ptr, s.size(), s.c_str());
}

fortran代码

MODULE os_dtoa_format_module
  ! Access the  real and character kinds being used in the Fortran code.
  USE Kinds, ONLY: rk, ck
  IMPLICIT NONE
  ! Type to wrap a deferred length component such that it can be passed 
  ! through the C++ code.
  TYPE FString
    CHARACTER(KIND=ck,LEN=:), ALLOCATABLE :: item
  END TYPE FString
CONTAINS
  ! Function for Fortran client code to call to invoke the C++ 
  ! function of interest.
  FUNCTION os_dtoa_format_fortran(x) RESULT(str)
    USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_DOUBLE, C_LOC
    REAL(rk), INTENT(IN) :: x
    CHARACTER(KIND=ck,LEN=:), ALLOCATABLE :: str
    INTERFACE
      ! Interface of the interoperable extern "C" C++ wrapper.
      SUBROUTINE os_dtoa_format_wrapper(x, fstring_ptr)  &
          BIND(C, NAME='os_dtoa_format_wrapper')
        USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_DOUBLE, C_PTR
        IMPLICIT NONE
        REAL(C_DOUBLE), INTENT(IN), VALUE :: x
        TYPE(C_PTR), INTENT(IN), VALUE :: fstring_ptr
      END SUBROUTINE 
    END INTERFACE
    ! Object used to pass the deferred length componnt through the 
    ! C++ code.
    TYPE(FString), TARGET :: f_str
    !****
    ! Call the C++ wrapper, perhaps converting the real kind.  Also 
    ! pass the asddress of the object with the deferred length 
    ! component.
    CALL os_dtoa_format_wrapper(REAL(x, C_DOUBLE), C_LOC(f_str))
    ! Move the deferred length string into the function result.
    CALL MOVE_ALLOC(f_str%item, str)
  END FUNCTION os_dtoa_format_fortran

  ! Utility function to be called from C/C++ to copy a char array 
  ! (a C string) into a Fortran allocatable deferred length 
  ! character component.
  SUBROUTINE set_fortran_string(fstring_ptr, length, str)  &
      BIND(C, NAME='set_fortran_string')
    USE, INTRINSIC :: ISO_C_BINDING, ONLY:  &
        C_PTR, C_CHAR, C_INT, C_F_POINTER
    ! The C address of the object that holds the deferred length 
    ! character component.
    TYPE(C_PTR), INTENT(IN), VALUE :: fstring_ptr
    ! The length of the char array.
    INTEGER(C_INT), INTENT(IN), VALUE :: length
    ! The char array.
    CHARACTER(KIND=C_CHAR), INTENT(IN) :: str(length)
    ! Fortran pointer to the object referenced by fstring_ptr that 
    ! holds the deferred length character component.
    TYPE(FString), POINTER :: f_str
    ! Declare type of the string index (F2003 doesn't allow inline 
    ! type declaration in a forall header - F2008 does).
    INTEGER :: i
    !****
    ! Associate the Fortran pointer with the object referenced by the 
    ! C address.
    CALL C_F_POINTER(fstring_ptr, f_str)
    ! Allocate the deferred length component to the given length.
    ALLOCATE(CHARACTER(length) :: f_str%item)
    ! Copy over the data.
    FORALL (i=1:length) f_str%item(i:i) = str(i)
  END SUBROUTINE set_fortran_string
END MODULE os_dtoa_format_module