Tang Laoya
Tang Laoya

Reputation: 145

How to pass C++ pointer to Fortran?

I have the following C++ code:

extern "C" void C_ASSIGN_ARRAY_TO_FORTRAN(double *doublearray)
{
    doublearray=new double [10];
    for (int i=0;i<10;i++)
        doublearray[i]=i;
}

The array doublearray should be passed to Fortran:

  USE, INTRINSIC :: ISO_C_BINDING
  IMPLICIT NONE
  INTERFACE
    SUBROUTINE C_ASSIGN_ARRAY_TO_FORTRAN(cdoublearray) BIND(C, NAME='C_ASSIGN_ARRAY_TO_FORTRAN')
    USE, INTRINSIC :: ISO_C_BINDING
      IMPLICIT NONE
      TYPE(C_PTR)  :: cdoublearray
    END SUBROUTINE 
  END INTERFACE

  TYPE(C_PTR) :: cdoublearray
  REAL(C_DOUBLE), POINTER :: fdoublearray(:)
  CALL C_ASSIGN_ARRAY_TO_FORTRAN((cdoublearray))
  CALL C_F_POINTER( cdoublearray, fdoublearray,[10])  
  WRITE (*, *) fdoublearray
  END   

However, the code crashed at C_F_POINTER: after calling C_ASSIGN_ARRAY_TO_FORTRAN, cdoublearray is equal to 0. Could anyone help me to take a look at it?

Upvotes: 2

Views: 1728

Answers (2)

Alexander Vogt
Alexander Vogt

Reputation: 18118

You are passing the pointer by value, and not by reference. Your C++ code should read

extern "C" void C_ASSIGN_ARRAY_TO_FORTRAN(double *& doublearray)
{
    doublearray=new double [10];
    for (int i=0;i<10;i++)
        doublearray[i]=i;
}

Note the C_ASSIGN_ARRAY_TO_FORTRAN(double *& doublearray).

An alternative way using C Pointers (thanks Vladimir) could look like:

extern "C" void C_ASSIGN_ARRAY_TO_FORTRAN(double ** doublearray)
{
    double *arr = new double [10];
    for (int i=0;i<10;i++) 
        arr[i]= i;
    *doublearray = arr;
}

Using the fix that Vladimir suggested, the Fortran code reads

program test
  USE, INTRINSIC :: ISO_C_BINDING
  IMPLICIT NONE
  INTERFACE
    SUBROUTINE C_ASSIGN_ARRAY_TO_FORTRAN(cdoublearray) BIND(C, NAME='C_ASSIGN_ARRAY_TO_FORTRAN')
    USE, INTRINSIC :: ISO_C_BINDING
      IMPLICIT NONE
      TYPE(C_PTR)  :: cdoublearray
    END SUBROUTINE 
  END INTERFACE

  TYPE(C_PTR) :: cdoublearray
  REAL(C_DOUBLE), POINTER :: fdoublearray(:)

  CALL C_ASSIGN_ARRAY_TO_FORTRAN( cdoublearray )
  CALL C_F_POINTER( cdoublearray, fdoublearray,[10])

  WRITE (*, *) 'fdoublearray',fdoublearray
END program

Then, the output is

./a.out 
 fdoublearray   0.0000000000000000        1.0000000000000000        2.0000000000000000        3.0000000000000000        4.0000000000000000        5.0000000000000000        6.0000000000000000        7.0000000000000000        8.0000000000000000        9.0000000000000000 

Upvotes: 1

You are passing a copy of the pointer here

CALL C_ASSIGN_ARRAY_TO_FORTRAN((cdoublearray))

the copy is made by the second set of parentheses. Therefore the cdoublearray is never changed and keeps the original undefined value which happens to e 0.

Try

CALL C_ASSIGN_ARRAY_TO_FORTRAN(cdoublearray)

but be careful, you will still have a problem when deallocating the array. That must be done from C++.

You must also adjust the procedure to accept a pointer to pointer. See @AlexenderVogt's answer.

Upvotes: 2

Related Questions