Return string from Fortran to C++

后端 未结 2 1340
北荒
北荒 2021-01-06 03:02

I have the following function call in C++:

int strLength = 20;
char* name;

getName(name, strLength);

printf(\"name: %s\\n\", name);

and i

相关标签:
2条回答
  • 2021-01-06 03:52

    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).

    0 讨论(0)
  • 2021-01-06 03:52

    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.

    Solution

    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
    
    0 讨论(0)
提交回复
热议问题