可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I am a fresh in programming, I wanna to call a fortran function in my c++ code. the thing is I dont know how to pass a fortran character*81 array to my c++.
fortran code is like:
subroutine func01(a) implicit none character*81 a(2) write(*,*) a(1) write(*,*) a(2) end
c++ code is like:
#include <iostream> extern "C"{ void func01_( const char **a ); } int main() { const char *a[2]; a[0]="Hello world!"; a[1]="This is a test!"; func01_(a); return 0; }
I bascially tested my fortran code using this
program pro01 character*81 a(2) a(1)='Hello world!' a(2)='This is a test!' call func01(a) end program pro01
'func01(a)' works well.
thanks to @PaulMcKenzie, I corrected some fool problems.....
However, when i compiled cpp code, the result went like messy codes like:
what should I do?
回答1:
The following code seems to work for gcc4 on Linux(x86_64), but it is not clear whether it is also valid for other platforms. (As suggested above, C-interoperability of modern Fortran may be useful.)
func01.f90
subroutine func01( a ) character(*) :: a( 2 ) print * print *, "char length = ", len(a(1)), len(a(2)) print *, "raw a(1) : [", a(1), "]" print *, "raw a(2) : [", a(2), "]" print *, "trim : [", trim(a(1)), "] [", trim(a(2)), "]" end
main.cpp
extern "C" { void func01_( char *c, const int len ); } #include <iostream> #include <cstring> // for memset() int main() { const int lenmax = 30, numstr = 3; // changed char length to 30 to fit in the terminal char a[ numstr ][ lenmax ]; std::string str[ numstr ]; str[0] = "moon"; str[1] = "mercury"; str[2] = "jupiter"; for( int k = 0; k < numstr; k++ ) { memset( a[k], ' ', lenmax ); // fill space str[k].copy( a[k], lenmax ); // copy at most lenmax char (no \0 attached) } func01_( a[0], lenmax ); func01_( a[1], lenmax ); // pass from mercury return 0; }
Compile
$ g++ func01.f90 main.cpp -lgfortran
Result
char length = 30 30 raw a(1) : [moon ] raw a(2) : [mercury ] trim : [moon] [mercury] char length = 30 30 raw a(1) : [mercury ] raw a(2) : [jupiter ] trim : [mercury] [jupiter]
回答2:
Here is a portable solution to pass an array of arbitrary length strings from C to Fortran.
I used a C++ file very similar to your own:
#include <iostream> extern "C" void func01(const char **a); int main() { const char *a[2] = {"Hello World","This is a test"}; func01(a); return 0; }
The only changes above are the initialization of the character arrays and removing the not-so-portable underscoring of the Fortran function. Instead we will be using standard C interoperability provided by Fortran 2003. The Fortran implementation of func01
becomes:
subroutine func01(cstrings) bind(C,name="func01") use, intrinsic :: iso_c_binding, only: c_ptr, c_char, c_f_pointer implicit none type(c_ptr), dimension(2), target, intent(in) :: cstrings character(kind=c_char), pointer :: a1(:), a2(:) ! size_t strlen(char * s); interface function strlen(s) bind(C, name='strlen') use, intrinsic :: iso_c_binding, only: c_ptr, c_size_t implicit none type(c_ptr), intent(in), value :: s integer(c_size_t) :: strlen end function strlen end interface call c_f_pointer(cstrings(1), a1, [strlen(cstrings(1))]) call c_f_pointer(cstrings(2), a2, [strlen(cstrings(2))]) write (*,*) a1 write (*,*) a2 end subroutine func01
The bind
attribute is what gives us interoperability with C for the function name and we are using C types for variables. The variable cstrings
will take an array of 2 pointers, or in C, *[2]
or **
. The bulk of the procedure is an interface block which lets us call the standard C library routine strlen
to make our life easier with the following calls to c_f_pointer
which translates a C pointer to a Fortran pointer.
When compiled and run, the output, as expected, is:
$ ./string-array-test Hello World This is a test
Compiled and tested with gcc 5.1.0.