Pass declared var types: F90 to C

I’ve read Chapters 9 and 10 of the PGI User’s Manual as well as lots of other web sites on calling C from Fortran but still can’t solve my particular problem of passing a declared variable type from Fortran 90 to C. The declared variable type also contains several pointers, which may be contributing to my problem.

I tried adding the SEQUENCE parameter to the declared variable, but that didn’t seem to make a difference. As shown below, the major symptom appears to be that not all of the pointer addresses make it through to the C function.

The Fortran 90 main code looks like this:

! =================================
  PROGRAM test
! =================================

  integer,parameter :: rd = SELECTED_REAL_KIND(p=12,r=37)

  TYPE :: gen_vertex
    SEQUENCE
    real(kind=rd) :: x
    real(kind=rd) :: y
  END TYPE gen_vertex

  TYPE :: gen_vertex_list
    SEQUENCE
    integer :: num_vertices
    type(gen_vertex),pointer,dimension(:) :: vertex
  END TYPE gen_vertex_list

  TYPE :: gen_polygon
    SEQUENCE
    integer :: num_contours
    integer,pointer,dimension (:) :: hole
    type(gen_vertex_list),pointer,dimension (:) :: contour
  END TYPE gen_polygon

  TYPE(gen_polygon) :: spoly


! DEFINE POLYGON 

  spoly%num_contours = 2
  allocate(spoly%hole(spoly%num_contours))
  allocate(spoly%contour(spoly%num_contours))

  spoly%hole(1) = 1
  spoly%contour(1)%num_vertices = 3
  allocate(spoly%contour(1)%vertex(spoly%contour(1)%num_vertices))
  spoly%contour(1)%vertex(1)%x = 0.0d0
  spoly%contour(1)%vertex(1)%y = 0.0d0
  spoly%contour(1)%vertex(2)%x = 1.0d0
  spoly%contour(1)%vertex(2)%y = 0.0d0
  spoly%contour(1)%vertex(3)%x = 1.0d0
  spoly%contour(1)%vertex(3)%y = 1.0d0
  spoly%hole(2) = 0
  spoly%contour(2)%num_vertices = 3
  allocate(spoly%contour(2)%vertex(spoly%contour(2)%num_vertices))
  spoly%contour(2)%vertex(1)%x = 0.0d0
  spoly%contour(2)%vertex(1)%y = 0.0d0
  spoly%contour(2)%vertex(2)%x = 2.0d0
  spoly%contour(2)%vertex(2)%y = 0.0d0
  spoly%contour(2)%vertex(3)%x = 2.0d0
  spoly%contour(2)%vertex(3)%y = 2.0d0


! CALL GPC (THE SCENIC ROUTE)
  call gen_test( spoly )


END PROGRAM test

The C routine looks like this:

#include <stdlib.h>

typedef struct
{
  double              x;
  double              y;
} gen_vertex;

typedef struct
{
  int                 num_vertices;
  gen_vertex         *vertex;
} gen_vertex_list;

typedef struct
{
  int                 num_contours;
  int                *hole;
  gen_vertex_list    *contour;
} gen_polygon;

void gen_test_(gen_polygon *subj )
{
   int i,j;

   printf("\n output from the C routine\n");
   printf(" address of subj = %p\n",subj );
   printf(" address of subj->hole = %p\n",subj->hole ); 
   printf(" address of subj->contour = %p\n",subj->contour ); 
   printf(" num_contours = %d\n",subj->num_contours );

   for (i=0; i < subj->num_contours; i++) {
      printf(" num_vertices = %d\n",subj->contour[i].num_vertices );
      printf(" hole         = %d\n",subj->hole[i] );

     for (j=0; j < subj->contour[i].num_vertices; j++) {
         printf(" vertex[%d].x  = %f\n",j,subj->contour[i].vertex[j].x );
         printf(" vertex[%d].y  = %f\n",j,subj->contour[i].vertex[j].y );
     }
   } 

   return;
}

The compilation (using version 5.2-1 for both pgf90 and pgcc) looks like this:

pgcc -c testc.c
pgf90 test.f90 testc.o -o test

Finally, the output looks like this:

 output from the C routine
 address of subj = 0x520b30
 address of subj->hole = 0x524850
 address of subj->contour = (nil)
 num_contours = 2
Segmentation fault

Any help — either specific or generally relating to passing declared variable types and/or pointers from Fortran90 to C — would be greatly appreciated. I similarly struggled with a different approach where I tried to pass just one pointer to an integer array to a C routine, free and re-allocate the pointer within the C routine, and then pass it back, so if anyone can suggest further reading on passing pointers back and forth between Fortran90 and C, that would be great too!

Sorry for the long post!

David

[/code]

Hi David,

You need to account for the Fortran descriptor and put some padding in your C structs.

Your testc.c should be changed to the following.

#include <stdlib.h> 
#ifdef __x86_64__
#define DESC_LEN 19
#else
#define DESC_LEN 17
#endif

typedef struct 
{ 
  double              x; 
  double              y; 
} gen_vertex; 

typedef struct 
{ 
  int                 num_vertices; 
  gen_vertex         *vertex; 
  int                 v_desc[DESC_LEN];
} gen_vertex_list; 

typedef struct 
{ 
  int                 num_contours; 
  int                *hole; 
  int                h_desc[DESC_LEN];
  gen_vertex_list    *contour; 
  int                c_desc[DESC_LEN];
} gen_polygon;

While this will work for this case, it is definately not portable. Also note that the descriptor length may change with each new release of the compiler. I determined the descriptor length by running a.out in pgdbg and printing spoly.

  • Mat