Return a string from Fortran in C ++

I have the following function call in C ++:

int strLength = 20; char* name; getName(name, strLength); printf("name: %s\n", name); 

and in Fortran:

 subroutine getName(name) bind (c, name='GETNAME') use,intrinsic :: iso_c_binding implicit none character, intent(out) :: name name = 'Martin' end subroutine getName 

When I execute the C ++ routine, the output is: name: M Now, I suppose this happens because character, intent(out) :: name declares a name variable of size 1, but if I change the declaration to this: character(len=6), intent(out) :: name I get this error message is: Error: Character argument 'name' at (1) must be length 1 because procedure 'getname' is BIND(C) . I also tried this: character(len=6,kind=c_char), intent(out) :: name , with the same error message. Finally, I tried this declaration: character(c_char),dimension(6), intent(out) :: name , which compiles but gives this result: name: MMMMMM .

My question boils down to: How can I return a string from Fortran in C ++?

+5
source share
2 answers

This Fortran-based function approach is neat and tidy, and is well-suited when a string has not yet been set (or memory allocated for it) in routine C. Note that you do not need to pass a string length argument or use an array of the intended size to create / return a string value. 1

The Fortran character string constant is used, so this function can be reused for any string.

The integer argument is also passed to the Fortran function to demonstrate, for example, how you can specify what the desired response should be.

Note that in this example, “intent (out)” is used to indicate that the integer argument does not need to be determined before passing, but it can be updated before it is returned. Therefore, you can change its value and return it to the calling program to use it as a “return code” instead.

Fortran Function

 ! f_string.f90 ! Called from C routine as: `myString = get_string(rc)` function get_string(c_rc) bind(c, name='get_string') use, intrinsic :: iso_c_binding implicit none integer(c_int), intent(out) :: c_rc ! <- Pass by reference; acts as return code in this example. type(c_ptr) :: get_string ! <- C_PTR to pass back to C character(len=:), allocatable, target, save :: fortstring ! <- Allocatable/any length is fine fortstring = "Append C_NULL_CHAR to any Fortran string constant."//C_NULL_CHAR get_string = c_loc(fortstring) ! <- C_LOC intrinsic gets loc of our string. c_rc = 1 ! <- Set the return code value. end function get_string 

Program C

 // c_string.c #include <stdio.h> #include <string.h> #include <stdlib.h> char *get_string(int *rc); // <- The Fortran function signature. int main(){ int rc; // <- No value set. char *mynameptr; // <- Just a plain ol' char *, no memory allocation needed. mynameptr = get_string(&rc); printf("mynameptr=%s\n", mynameptr); printf("len =%d\n", strlen(mynameptr)); printf("rc =%d\n", rc); return rc; } 

Compilation, call, output:

 ifort /c f_string.f90 icl c_string.c /link f_string.obj c_string.exe # example output: # mynameptr=Append C_NULL_CHAR to any Fortran string constant. # len =48 # rc =1 

1 It is also easy to compile without warning (what happens to the OP solution without the change that I suggested in my comments).

+4
source

The problem was to assign an array of characters of rank n scalar character of length n , which was discussed in this question. Changing the Fortran procedure as shown below solved the problem.

Decision

Since I work in the old system, I needed to find the solution indicated below. Obviously, this is not exactly the same, but it still shows the general structure. If anyone else has to make this decision, you should probably follow the recommendations in Matt P.'s comment.

Although this is the solution I went to, I feel that the answer from Matt P is the best solution to the general problem, as indicated in the title of the question, so I accepted this as the answer.

C ++

 int strLength = 20; char* name = new char[strLength]; getName(name, strLength); printf("name: %s\n", name); 

Fortran

 subroutine getName(name) bind (c, name='GETNAME') use,intrinsic :: iso_c_binding implicit none character(c_char),dimension(20), intent(out) :: name character(20) :: fName fName = 'Martin'//c_null_char do j=1,len(fName ) name(j) = fName (j:j) enddo end subroutine getName 
+1
source

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


All Articles