I have the following function call in C++:
int strLength = 20;
char* name;
getName(name, strLength);
printf(\"name: %s\\n\", name);
and i
This Fortran function-based approach is neat and tidy, and is quite suitable when the string has not yet been set (or had memory allocated for it) in the C routine. Notice that you do not need to pass in a string length argument, or use an assumed-size array to build/return a string value.1
A Fortran allocatable character string constant is used, so that this function is reusable for any string.
An integer argument is also passed into the Fortran function to demonstrate, for example, how you may indicate what the desired response should be.
Notice that in this example "intent(out)" is used to indicate that the integer argument does not need to be defined before being passed in, but that it may be updated before it is returned. Therefore, you can modify its value and return it to the calling program so that it may instead be used as a "return code".
The 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
The C Program
// 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;
}
Compile, 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 This also compiles cleanly without warnings (which do occur with the OP's solution without the modifications I suggested in its comments).
The problem was in assigning a character array of rank n
to a character scalar of length n
, which was addressed in this question. Changing the Fortran routine as shown below solved the issue.
Since I'm working in a legacy system I had to go for the solution indicated below. Obviously it's not exactly the same, but it still shows the general structure. If anyone else should go for this solution as well you should probably follow the recommendations in Matt P's comment.
Although this is the solution I went for, I feel like the answer from Matt P is a better solution to the general problem as stated in the question title, which is why I accepted that 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