mlzerkle@athena.mit.edu (Michael L Zerkle) (11/10/90)
I am trying to develop C functions to allocate and deallocate arrays for use in a FORTRAN progam that would run on a number of different UNIX boxes (DEC VS3100, Apollo, SGI 4D/210, etc.). The C functions I have written appear to allocate the double array correctly, but either it does not pass it back the the FORTRAN program correctly, or the FORTRAN program is not accepting the pointer/array it is returning. Does anyone out there have any experience with problems of this sort, or know what I am doing wrong? Any suggestions? Basic info: f77 compiler on SGI 4D/210 ANSI C compiler on SGI 4D/210 same problem on other UNIX systems. Thanks in advance for any help. Mike Zerkle mlzerkle@athena.mit.edu ******************** * Fortran Code ... * ******************** program testgetm real*8 a(1) integer*4 maxa,bytesa,i external getmd,freemd c maxa=5 bytesa=8 c c Write Initial location. c write(6,'(a)') 'Initial address' write(6,*) loc(a),maxa,bytesa c c Allocate real*8 array. c call getmd(a,maxa) c c Write addresses c write(6,'(a)') 'Final address' write(6,*) loc(a),maxa,bytesa c c Work on array c write(6,'(a)') 'REAL*8 array ' if (loc(a).ne.0) then do 10 i=1,maxa c a(i)= 1.0d+0*i write(6,*) i, a(i) 10 continue else write(6,'(a)') ' Unable to allocate r*8 array a' endif c c Free arrays. c if (loc(a).ne.0) call freemd(a) c stop end ************** * C Code ... * ************** #include <stdlib.h> void getmd_(double *array, int *nelem) { printf("org array addr = %ld\n",array); array = (double *) calloc((size_t) *nelem, (size_t) sizeof(double)); printf("new array addr = %ld\n",array); } void freemd_(double *array) { free((void *) array); } ********************* * Sample output ... * ********************* Initial address 29996 5 8 org array addr = 29996 new array addr = 54272 Final address 29996 5 8 REAL*8 array 1 0. 2 0. 3 0. 4 1.1840974637956d+30 5 5.2810833895564d-20
bron@bronze.wpd.sgi.com (Bron Campbell Nelson) (11/13/90)
In article <1990Nov9.210442.27086@athena.mit.edu>, mlzerkle@athena.mit.edu (Michael L Zerkle) writes: > I am trying to develop C functions to allocate and deallocate arrays > for use in a FORTRAN progam that would run on a number of different > UNIX boxes (DEC VS3100, Apollo, SGI 4D/210, etc.). The C functions > I have written appear to allocate the double array correctly, but > either it does not pass it back the the FORTRAN program correctly, or > the FORTRAN program is not accepting the pointer/array it is returning. > > Does anyone out there have any experience with problems of this sort, > or know what I am doing wrong? Any suggestions? > I'll skip over the error in the code and instead mention one way that you can do this using SGI Fortran. It relys on a couple of things: (1) Fortran array parameters are passed simply by passing the address (no funny array descriptors or dope vectors) (2) The VAX Fortran "%val" extension. These two assumptions are true with SGI Fortran, and are probably true on a number of other platforms. For instance, the following program will behave like one would hope: integer foo foo = malloc(1000*1000*4) call fill(%VAL(foo), 1000,1000) end subroutine fill(a,i,j) real a(i,j) do n1 = 1, 1000 do n2 = 1, 1000 a(n2,n1) = 0.0 enddo enddo return end Some versions of the SGI software do not define a Fortran interface to malloc. In such a case you'll also have to write the 1 line C routine int malloc_(size) int *size; { return (int) malloc(*size); } -- Bron Campbell Nelson bron@sgi.com or possibly ..!ames!sgi!bron These statements are my own, not those of Silicon Graphics.
jim@interet.UUCP (User) (11/15/90)
In article <1990Nov9.210442.27086@athena.mit.edu>, mlzerkle@athena.mit.edu (Michael L Zerkle) writes: > I am trying to develop C functions to allocate and deallocate arrays > for use in a FORTRAN progam that would run on a number of different > UNIX boxes (DEC VS3100, Apollo, SGI 4D/210, etc.). > > program testgetm > real*8 a(1) > > call getmd(a,maxa) This call overwrites the address of a, which I believe is incorrect, although it may work on certain platforms. The "a" address is a constant within the meaning of Fortran. > void getmd_(double *array, int *nelem) It is dangerous to declare nelem an int pointer. It is far better to de- clare it a long pointer, since all fortrans I know treat most variables as four bytes, or long. This even applies to logical. We allocate storage for Fortran programs as follows: subroutine dostuf(a,maxa) integer maxa double precision a(maxa) .... massive great things happen .... end The real work is done in dostuf, and Fortran expects a pointer "a" which you provide by calling it from c. void ccall_(nelem) /* used to call dostuf_() with needed storage */ long *nelem; /* size of array needed */ { double *array; /* just an example, not tested */ array = (double *) calloc((size_t) *nelem, (size_t) sizeof(double)); dostuf_(array, nelem); free((void *) array); } You must call ccall() from Fortran after Fortran figures out how big the array needs to be: program myprog ... c we need isize elements. call ccall(isize) c large job returns. ... end The above is highly portable, except that you have the portability problem of linking c and Fortran in the first place. Your solution is more gen- eral and powerful, but I would be concerned with the portability. I hope this helps. In our shop, we solve the problem of linking Fortran with c first, and we will not use hardware for which this is not easy. Then we solve all other portability problems by writing in either c or Fortran as appropriate. Storage allocation is portable in c, so c is used in the above example. Note that f2c solves the problem of linking Fortran with c. Jim uunet!interet!jim