Passing char arrays from C ++ to fortran

I am unable to pass char arrays from C ++ to fortran (f90).

Here is my C ++ file, 'cmain.cxx':

#include <iostream> using namespace std; extern "C" int ftest_( char (*string)[4] ); int main() { char string[2][4]; strcpy(string[0],"abc"); strcpy(string[1],"xyz"); cout << "c++: string[0] = '" << string[0] << "'" << endl; cout << "c++: string[1] = '" << string[1] << "'" << endl; ftest_(string); return 0; } 

Here is my fortran file, 'ftest.f90':

 SUBROUTINE FTEST(string) CHARACTER*3 string(2) CHARACTER*3 expected(2) data expected(1)/'abc'/ data expected(2)/'xyz'/ DO i=1,2 WRITE(6,10) i,string(i) 10 FORMAT("fortran: string(",i1,") = '", a, "'" ) IF(string(i).eq.expected(i)) THEN WRITE(6,20) string(i),expected(i) 20 FORMAT("'",a,"' equals '",a,"'") ELSE WRITE(6,30) string(i),expected(i) 30 FORMAT("'",a,"' does not equal '",a,"'") END IF ENDDO RETURN END 

Build process:

 gfortran -c -m64 ftest.f90 g++ -c cmain.cxx gfortran -m64 -lstdc++ -gnofor_main -o test ftest.o cmain.o 

Edit: note that the executable can also be created with:

 g++ -lgfortran -o test ftest.o cmain.o 

Also, the -m64 flag is required since I am running OSX 10.6.

The result of executing 'test':

 c++: string[0] = 'abc' c++: string[1] = 'xyz' fortran: string(1) = 'abc' 'abc' equals 'abc' fortran: string(2) = 'xy' 'xy' does not equal 'xyz' 

Declaring arrays of characters 'string' and 'expected' in ftest.f90 with a size of 4, i.e.:

 CHARACTER*4 string(2) CHARACTER*4 expected(2) 

and recompiling gives the following result:

 c++: string[0] = 'abc' c++: string[1] = 'xyz' fortran: string(1) = 'abc' 'abc' does not equal 'abc ' fortran: string(2) = 'xyz' 'xyz' does not equal 'xyz ' 

Declaring character arrays in 'cmain.cxx' with size 3, that is:

 extern "C" int ftest_( char (*string)[3] ); int main() { char string[2][3]; 

and return to the original size in the fortran (3) file, that is:

 CHARACTER*3 string(2) CHARACTER*3 expected(2) 

and recompiling gives the following result:

 c++: string[0] = 'abcxyz' c++: string[1] = 'xyz' fortran: string(1) = 'abc' 'abc' equals 'abc' fortran: string(2) = 'xyz' 'xyz' equals 'xyz' 

So, the last case is the only one that works, but here I assigned 3 characters to a char array of size 3, which means that the termination "\ 0" is missing, and leads to the output of "abcxyz" - this is not acceptable for my intended application.

Any help would be greatly appreciated, it drives me crazy!

+6
source share
3 answers
Lines

C have a zero end, while fortran lines, by convention, are filled with a space, but a fixed size. You should not expect to be able to pass C strings to fortran without any conversion.

For instance:

 #include <algorithm> void ConvertToFortran(char* fstring, std::size_t fstring_len, const char* cstring) { std::size_t inlen = std::strlen(cstring); std::size_t cpylen = std::min(inlen, fstring_len); if (inlen > fstring_len) { // TODO: truncation error or warning } std::copy(cstring, cstring + cpylen, fstring); std::fill(fstring + cpylen, fstring + fstring_len, ' '); } 

What you can use with either a version of length 3 or 4 ftest :

 #include <iostream> #include <ostream> extern "C" int ftest_( char string[][4] ); void ConvertToFortran(char* fstring, std::size_t fstring_len, const char* cstring); int main() { char cstring[2][4] = { "abc", "xyz" }; char string[2][4]; ConvertToFortran(string[0], sizeof string[0], cstring[0]); ConvertToFortran(string[1], sizeof string[1], cstring[1]); std::cout << "c++: string[0] = '" << cstring[0] << "'" << std::endl; std::cout << "c++: string[1] = '" << cstring[1] << "'" << std::endl; ftest_(string); return 0; } 
+10
source

I recommend using Fortran's ISO C binding, as suggested by the High Performance Mark. You are already using extern C. The ISO C binding for Fortran 2003 (currently implemented in most Fortran 95 / partial Fortan 2003 compilers) makes this approach independent of the compiler and platform. Charles Bailey described the differences between the lines in two languages. This question in Stackoverflow has an example code: Calling a FORTRAN routine with C

If you do not want to modify existing Fortran code, you can write a "glue" routine between your C ++ code and existing Fortran code. Writing a gluing procedure in Fortran using an ISO C binding would be more reliable and stable, as it would be based on language specifics.

+5
source

The above examples are too heavy, if you do not want to pass more than one line, you can use the parameter of "hidden" length ...

 extern "C" void function_( const char* s, size_t len ) { std::string some_string( s, 0, len ); /// do your stuff here ... std::cout << "using string " << some_string << std::endl; /// ... } 

which you can call from fortran for example

  call function( "some string or other" ) 

You do not need to worry about individual copy operations, as the std :: string constructor can do everything for you.

+1
source

Source: https://habr.com/ru/post/913250/


All Articles