On Friday, May 14, 2021 at 10:18:53 AM UTC-4,
duhd...@gmail.com wrote:
> ..
> 2. I would try writing a wrapper if necessary. Thanks for the suggestion.
> ..
@Haodong Du,
Can you please first share if plan to do any additional work using Fortran? If so, I strongly suggest you also use the Fortran Discourse site where it is much easier to engage with Fortranners in terms of markdown, file attachments, images, etc. in posts:
https://fortran-lang.discourse.group/
Secondly, if you have a Fortran procedure whose interface is known and toward which you are *willing* to write wrapper(s) using *modern* facilities to consume said procedure in different contexts, here is an illustration I would recommend using the example you have provided.:
--- begin Fortran code ---
subroutine fortfunc(ii,ff,aa,ss)
! Mimic the Fortran procedure here
integer :: ii
real*8 :: ff
real*8, dimension(3,3) :: aa
character(len=10) :: ss
write(*,*) "Passed to Fortran"
write(*,*) ss
write(*,*) ii, ff
write(*,*) aa
ii = 2
ff = 3.1415
aa = reshape((/1,2,3,4,5,6,7,8,9/),shape(aa))
ss = "there" // CHAR(0)
return
end
module wrap_func_m
! Wrapper for the Fortran procedure
use, intrinsic :: iso_c_binding, only : c_int, c_double, c_char
interface
subroutine fortfunc(ii,ff,aa,ss)
integer :: ii
real*8 :: ff
real*8, dimension(3,3) :: aa
character(len=10) :: ss
end subroutine
end interface
contains
subroutine wrap_func(ii, ff, aa, ss, irc) bind(C, name="wrap_func")
integer(c_int), intent(inout) :: ii
real(c_double), intent(inout) :: ff
real(c_double), intent(inout), target :: aa(:,:)
character(kind=c_char,len=*), intent(inout), target :: ss
integer(c_int), intent(inout), optional :: irc
! Error handing here; do the needful
if ( size(aa,dim=1) < 3 ) then
print *, "wrap_func: ", size(aa,dim=1)
if ( present(irc) ) irc = 1 ! or error stop if appropriate
return
end if
if ( len(ss) < 10 ) then
print *, "wrap_func: ", len(ss)
if ( present(irc) ) irc = 2 ! or error stop if appropriate
return
end if
block
real(c_double), pointer :: a(:,:)
character(kind=c_char,len=10), pointer :: s
a => aa(1:3,1:3)
s => ss
call fortfunc(ii,ff,aa,ss)
end block
end subroutine
end module
--- end Fortran code ---
--- begin C++ code ---
#include <iostream>
#include <cstring>
#include "ISO_Fortran_binding.h"
using namespace std;
extern "C" {
// Prototype for the Fortran procedure
void wrap_func(int *, double *, CFI_cdesc_t *, CFI_cdesc_t *, int *);
}
int main()
{
int ii=1;
double ff=2.17;
double aa[3][3] = {0,0,0,0,0,0,0,0,0};
char ss[] = "abcdefghij";
size_t ll = strlen(ss);
cout << "original in C++" << endl;
cout << ii << " "<< ff << endl;
cout << ss << endl;
for(size_t n=0; n<3; n++) {
for (size_t m=0; m<3; m++) {
cout << aa[n][m];
}
}
cout << endl;
int rc = 0;
// Use macro to set aside an address to "description" of array data of rank-2
CFI_CDESC_T(2) a;
CFI_index_t extents[2] = { 3, 3 };
// Initialize the C descriptor as a rank-2 objeect of doubles
rc = CFI_establish((CFI_cdesc_t *)&a, (void *)aa, CFI_attribute_pointer, CFI_type_double, sizeof(double),
(CFI_rank_t)2, extents);
if (rc != CFI_SUCCESS) return rc;
// Use macro to set aside an address to "description" of string data
CFI_CDESC_T(0) str;
// Initialize the C descriptor as a scalar character nonpointer data type
rc = CFI_establish((CFI_cdesc_t *)&str, (void *)ss, CFI_attribute_other, CFI_type_char, ll, 0, NULL);
if (rc != CFI_SUCCESS) return rc;
wrap_func(&ii, &ff, (CFI_cdesc_t*)&a, (CFI_cdesc_t*)&str, &rc);
if (rc != 0) return rc;
cout << "passed back to C++" << endl;
cout << ii << " "<< ff << endl;
cout << ss << endl;
for(size_t n=0; n<3; n++) {
for (size_t m=0; m<3; m++) {
cout << aa[n][m] << " ";
}
cout << endl;
}
return rc;
}
--- end C++ code ---
Program behavior:
--- begin console output ---
C:\Temp>ifort /c /standard-semantics func.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.2.0 Build 20210228_000000
Copyright (C) 1985-2021 Intel Corporation. All rights reserved.
C:\Temp>cl /c /W3 /EHsc main.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.28.29337 for x64
Copyright (C) Microsoft Corporation. All rights reserved.
main.cpp
C:\Program Files (x86)\Intel\oneAPI\compiler\latest\windows\compiler\include\ISO_Fortran_binding.h(156): warning C4200: nonstandard extension used: zero-sized array in struct/union
C:\Program Files (x86)\Intel\oneAPI\compiler\latest\windows\compiler\include\ISO_Fortran_binding.h(156): note: This member will be ignored by a defaulted constructor or copy/move assignment operator
main.cpp(41): warning C4200: nonstandard extension used: zero-sized array in struct/union
main.cpp(41): note: This member will be ignored by a defaulted constructor or copy/move assignment operator
C:\Temp>link main.obj func.obj /subsystem:console /out:main.exe
Microsoft (R) Incremental Linker Version 14.28.29337.0
Copyright (C) Microsoft Corporation. All rights reserved.
C:\Temp>main.exe
original in C++
1 2.17
abcdefghij
000000000
Passed to Fortran
abcdefghij
1 2.17000000000000
0.00000000000000 0.00000000000000 0.00000000000000
0.00000000000000 0.00000000000000 0.00000000000000
0.00000000000000 0.00000000000000 0.00000000000000
passed back to C++
2 3.1415
there
1 2 3
4 5 6
7 8 9
C:\Temp>
--- end console output ---
A couple of notes:
1) gfortran has incomplete implementation of support toward Fortran 2018 that hopefully some volunteer can pickup and resolve
2) With above, you can use the string class in C++ and also possibly STL vector container for array data, greatly easing the consumption of Fortran code on the C++ side