replica nfl jerseysreplica nfl jerseyssoccer jerseyreplica nfl jerseys forums.silverfrost.com :: View topic - Passing a Fortran type as struct to C
forums.silverfrost.com Forum Index forums.silverfrost.com
Welcome to the Silverfrost forums
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Passing a Fortran type as struct to C

 
Post new topic   Reply to topic    forums.silverfrost.com Forum Index -> Support
View previous topic :: View next topic  
Author Message
jjgermis



Joined: 21 Jun 2006
Posts: 404
Location: N�rnberg, Germany

PostPosted: Thu Sep 24, 2009 1:26 pm    Post subject: Passing a Fortran type as struct to C Reply with quote

In the same forum I mentioned a mix programming topic. This is sorted out. In the next step I would like to call a function in the C program. In oder to do so I need passing a Fortran user defined type as struct to the C subroutine. Only the standard types is explained in the documentaion under Win32 Platform -> Mixed language programming. Or at least fill the components of the struct.

A very simple example will help me to sort this out. Especially the how to handle the pointers Exclamation

For the sake of completeness I provide the C header-file with the struct definition:
Code:
struct triangulateio {
  REAL *pointlist;                                               /* In / out */
  REAL *pointattributelist;                                      /* In / out */
  int *pointmarkerlist;                                          /* In / out */
  int numberofpoints;                                            /* In / out */
  int numberofpointattributes;                                   /* In / out */

  int *trianglelist;                                             /* In / out */
  REAL *triangleattributelist;                                   /* In / out */
  REAL *trianglearealist;                                         /* In only */
  int *neighborlist;                                             /* Out only */
  int numberoftriangles;                                         /* In / out */
  int numberofcorners;                                           /* In / out */
  int numberoftriangleattributes;                                /* In / out */

  int *segmentlist;                                              /* In / out */
  int *segmentmarkerlist;                                        /* In / out */
  int numberofsegments;                                          /* In / out */

  REAL *holelist;                        /* In / pointer to array copied out */
  int numberofholes;                                      /* In / copied out */

  REAL *regionlist;                      /* In / pointer to array copied out */
  int numberofregions;                                    /* In / copied out */

  int *edgelist;                                                 /* Out only */
  int *edgemarkerlist;            /* Not used with Voronoi diagram; out only */
  REAL *normlist;                /* Used only with Voronoi diagram; out only */
  int numberofedges;                                             /* Out only */
};

#ifdef ANSI_DECLARATORS
void triangulate(char *, struct triangulateio *, struct triangulateio *,
                 struct triangulateio *);
void trifree(VOID *memptr);
#else /* not ANSI_DECLARATORS */
void triangulate();
void trifree();
#endif /* not ANSI_DECLARATORS */
Back to top
View user's profile Send private message
PaulLaidler
Site Admin


Joined: 21 Feb 2005
Posts: 8210
Location: Salford, UK

PostPosted: Thu Sep 24, 2009 4:44 pm    Post subject: Reply with quote

The Fortran will pass a reference (for anything). I guess that the C would pass a pointer by default so that would match the Fortran OK.

Fortran does not fix the order of the members unless you use a SEQUENCE statement. From memory I think the C order will be OK. If not then a #pragma may be required.

Not sure about any of the details but as usual the best way is just to try it and see what happens
Back to top
View user's profile Send private message AIM Address
jjgermis



Joined: 21 Jun 2006
Posts: 404
Location: N�rnberg, Germany

PostPosted: Sat Sep 26, 2009 3:05 pm    Post subject: Reply with quote

When one starts searching for mix language programming there are several websites which explains this. However, it seems like the detail syntax is somewhat compiler dependant. I tried a few things using FTN95. The C subroutines are as follows:
Code:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

struct type_t{
  int i;
  float x;
  float *y;
  char *str;
};

extern "C" int ctest(char *temp, int Length){
  printf("Here is the string written from c code: %s\n", temp);
  return 1;
};

extern "C" float mult(float a, float b){
  return a*b;
};

extern "C" void write_type(struct type_t xy){
  printf("xy.i: %d\n", xy.i);
  printf("xy.x: %6.4f\n", xy.x);
  printf("xy.y: %6.4f\n", *xy.y);
  printf("xy.y: %c\n", *xy.str);
};
The Fortran programm calling this routines is as follows:
Code:
program test
  implicit none

  C_EXTERNAL CTEST 'ctest'(REF) : INTEGER*4
  C_EXTERNAL MULT 'mult'(VAL,VAL) : REAL
  C_EXTERNAL WRITE_TYPE 'write_type'(VAL)
  C_EXTERNAL ASSIGN_POINTER 'assign_pointer'(REF)
   
  character(len=11) :: string='test phrase'
  integer*4 :: returnval
  integer*4 :: I

  REAL :: A, B, C

  type :: type_t
    integer :: i
    real    :: x
    real,pointer :: y
    character(len=20),pointer :: str      !<<<<<< ------ ???????
  end type type_t
  type(type_t) :: xy
 
  write(*,'("String written from fortan code: ",A)') string
 
  returnval = CTEST(string)
  write(*,'("Returned valued from c code: ",i4)') returnval

  A=4.0
  B=6.0
  C = mult(A,B)
  write(*,'("MULT: ",2F6.2)') C,(A*B)
 
  xy%i = 6
  xy%x = 9.5
  xy%y = 20.3
  xy%str = 'qwert'//char(0)
  call write_type(xy)
end

Question: How does one pass a string which is a component of a Fortran user defined type (see type_t in the above example)? In the given example only the first character is passed. Is it correct to terminate the string in Fortran with //char(0) before passing?
Back to top
View user's profile Send private message
PaulLaidler
Site Admin


Joined: 21 Feb 2005
Posts: 8210
Location: Salford, UK

PostPosted: Sat Sep 26, 2009 5:01 pm    Post subject: Reply with quote

In C you would need an array of char with the given length rather than a char*.
Back to top
View user's profile Send private message AIM Address
jjgermis



Joined: 21 Jun 2006
Posts: 404
Location: N�rnberg, Germany

PostPosted: Sun Sep 27, 2009 10:38 am    Post subject: Reply with quote

In the meanwhile I made good progress in using the C-code with FTN95. Passing a C-structure from FTN95 seems to work fine. However, my "arriving" data seem to be wrong. The program requires a list of x- and y-values which must be in pointlist. The latter needs to be dynamically allocated. A part of the module and the subroutine is listed below.
Code:
module cproc
  implicit none
  C_EXTERNAL TRIANGULATE 'triangulate'(REF,REF,REF,REF)
  type :: triangulateio
    real,dimension(:),pointer :: pointlist   
    integer  :: numberofpoints           
  end type triangulateio
end module cproc

subroutine poly(in)
  use cproc
  implicit none
  type(triangulateio),intent(out) :: in

  in%numberofpoints = 4
  allocate(in%pointlist(in%numberofpoints*2))
  in%pointlist(1) = 0.0
  in%pointlist(2) = 0.0
  in%pointlist(3) = 1.0
  in%pointlist(4) = 0.0
  in%pointlist(5) = 1.0
  in%pointlist(6) = 10.0
  in%pointlist(7) = 0.0
  in%pointlist(8) = 10.0
  return
end subroutine poly

program mesh
  use cproc
  implicit none
  type(triangulateio) :: tri

  call poly(tri)  ! Initilise tri
  ! C call: triangulate("pczAevn", &in, &mid, &vorout);
  ! -> assign the address of in, mid and vorout
  call triangulate('pczAevn'//char(0),tri,tri,tri)
 
end program mesh

Question: Is the allocation of the array correct (what about malloc)? Are there perhaps any obvious error in the above solution. The equivalent from the C example program is follows:

Code:
  in.numberofpoints = 4;
  in.pointlist = (REAL *) malloc(in.numberofpoints * 2 * sizeof(REAL));
  in.pointlist[0] = 0.0;
  in.pointlist[1] = 0.0;
  in.pointlist[2] = 1.0;
  in.pointlist[3] = 0.0;
  in.pointlist[4] = 1.0;
  in.pointlist[5] = 10.0;
  in.pointlist[6] = 0.0;
  in.pointlist[7] = 10.0;
Back to top
View user's profile Send private message
jjgermis



Joined: 21 Jun 2006
Posts: 404
Location: N�rnberg, Germany

PostPosted: Wed Sep 30, 2009 8:38 am    Post subject: Reply with quote

Regrettably, I could not resolve the issue of passing the data correct from Fortran to the C program. However, I could get the C program to compile with SCC. Thus, allowing us to build the program and use it as an standalone executealble.

Another advantage of FTN95 is that one can have .c and .f90 code in the same project. The compiler takes automatically care of the linking Smile
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    forums.silverfrost.com Forum Index -> Support All times are GMT + 1 Hour
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group