将数组从 C/C++ 传递到 Fortran 并返回计算的数组

2022-01-14 00:00:00 fortran arrays c fortran-iso-c-binding c++

我正在尝试将一个数组从 C/C++ 传递到 Fortran 2003 模块,并将计算值返回到 C/C++.我已经能够很好地传递和返回单个值(标量),但是来回获取 array 证明是困难的.我发现了很多关于标量值的线程,并且我已经成功地完成了这些工作.

I am trying to pass an array from C/C++ into a Fortran 2003 module and get the calculated values back into C/C++. I've been able to pass and return single values (scalars) just fine, but getting an array back and forth is proving difficult. I've found many threads on scalar values and I've been successful at making those work.

我已经按照我的工作标量函数对基于数组的函数进行了建模.

I've modeled my array based functions after my working scalar functions.

我正在使用 gcc/gfortran.

I am using gcc/gfortran.

这是 Fortran 模块 (ConvertUnitsLib.f03).

Here's the Fortran module (ConvertUnitsLib.f03).

module ConvertUnitsLib

use :: iso_c_binding ! for C/C++ interop
real(c_double), bind(c) :: degF, degC

public DegCtoF

contains

!
! Convert temperature degrees Celsius Fahrenheit
!
real(kind = c_double) function DegCtoF(degC) result(degF) &
    & bind(c, name = "DegCtoF")

    real(c_double), intent(in), dimension(:) :: degC
    real(c_double), dimension(size(degC)) :: degF

    do i = 1, size(degC)
        degF(i) = ( degC(i) * 1.8 ) + 32
    end do

end function DegCtoF


! End of module
end module ConvertUnitsLib

还有 C/C++,(CFort.cpp)

And the C/C++, (CFort.cpp)

#include <stdio.h>

#ifdef __cplusplus
extern"C" {
#endif
    double DegCtoF(double *[]);
#ifdef __cplusplus
}
#endif


/**********************************************************************/


int main(int argc, char *argv[])
{
    printf("C/C++ and Fortran together!
");

    double DegreesC[2] = {32, 64};
    double DegreesF[2];

    DegreesF = DegCtoF(&DegreesC);
    printf("%3.1f [C] = %3.1f [F]
", DegreesC, DegreesF );

    return 0;
}

最后但同样重要的是,Makefile

And last but not least, the Makefile

# C++ directives
CC=g++
CFLAGS=-std=c++11

# Fortran directives
FC=gfortran
FFLAGS=-std=f2003

all: clean
    $(FC) $(FFLAGS) -c -fcheck=all ConvertUnitsLib.f03
    $(CC) $(CFLAGS) -c CFort.cpp
    $(FC) $(FFLAGS) ConvertUnitsLib.o CFort.o -o convert

clean:
    rm -f *.o
    rm -f *.mod

推荐答案

在 francescalus 确认之前,我要说的是,据我所知,这有点陈旧,互操作性不允许您尝试做与数组.此外,一些好习惯在编码时总是至关重要的.例如,在 fortran 中使用 implicit none 强制在使用所有变量之前声明它们.在语言允许的情况下使用命名常量,例如您在 fortran 中用作数组大小的 2.

Before francescalus confirms it, I was going to say that from what I know that was a little bit old, the interoperability does not permit what you are trying to do with arrays. In addition, some good habits are always critical when coding. For example using implicit none in fortran to force the declaration of all variables before they are used. The use of named constant when the language permits it, for example the 2 that you are using as array size in fortran.

以下是您的代码的修改版本,它应该可以实现您想要实现的目标.

Below is a modified version of your code that should do something like what you want to achieve.

//Fortran

module ConvertUnitsLib

use :: iso_c_binding ! for C/C++ interop
!real(c_double), bind(c) :: degF, degC
implicit none

public DegCtoF

contains

!
! Convert temperature degrees Celsius Fahrenheit
!
subroutine DegCtoF(degC, degF, n)&
    bind(c, name = "DegCtoF")

    integer, intent(in) :: n
    real(c_double), intent(in), dimension(n) :: degC
    real(c_double), intent(out), dimension(n) :: degF
    integer :: i

    do i = 1, n
        degF(i) = ( degC(i) * 1.8 ) + 32
    end do

end subroutine DegCtoF

//C++

#include <stdio.h>

#ifdef __cplusplus
extern"C" {
    #endif
    double DegCtoF(double [], double [], const int *);
    #ifdef __cplusplus
}
#endif


/**********************************************************************/


int main(int argc, char *argv[])
{
    const int N = 2;
    printf("C/C++ and Fortran together!
");

    double DegreesC[N] = {32, 64};
    double DegreesF[N];

    DegCtoF(DegreesC, DegreesF, &N);
    for(int i = 0; i<N; i++){
        printf("%d : %3.1f [C] = %3.1f [F]
", i, DegreesC[i], DegreesF[i] );
    }

    return 0;
}

相关文章