我有一个带签名的c ++方法
extern std::string os_dtoa_format(double x);
我想从Fortran打来电话。我知道我必须构建一个显式接口,但我不确定如何去做。我对如何处理double有一个模糊的想法,但我还没有找到关于std :: string的任何信息。 char *似乎很难,这让我想问是否有可能做我想做的事。
答案 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