[comp.sys.sgi] Cross-Language Communication problem between FORTRAN & C.

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:
        SGI 4D/210VGXB
  	f77 compiler
        ANSI C compiler
	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

Keywords: 

bron@bronze.wpd.sgi.com (Bron Campbell Nelson) (11/13/90)

In article <1990Nov9.212649.27564@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.

calvin@dinkum.wpd.sgi.com (Calvin H. Vu) (11/13/90)

In <1990Nov9.212649.27564@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?

You cannot assign an address to an array at runtime to turn the array into a 
relocatable array.  On SGI systems,  the type POINTER is supported to allow
you to do this (see the latest F77 Reference Manual on POINTER specification
if you have one).  For example:
	real*8 a(1)
	pointer (ptr, a)
	maxa = 5
C   You have to use an assignment (or DATA statement) to give 'ptr' a value
C   since it doesn't have a storage allocated for it i.e. you cannot
C   use it as an actual argument and assign a value to it in the called
C   subroutine
	ptr = malloc(maxa*8)
	do i=1,maxa
	  a(i) = i
	enddo
	end
For systems which do not support POINTER type you can do the following
trick:
	integer ptr, maxa
	maxa = 5
	ptr = malloc(maxa*8)
	call malloc_array(%val(ptr)) !pass value of ptr to be used as address
	end
	subroutine malloc_array(a)
	dimension a(1)
	do i=1,maxa
	  a(i) = i
	enddo
	return
	end

The following is a modified version of your program which works on SGI
systems (and DEC).  

      program testgetm
      real*8 a(1)
      pointer (ptr, a)
      integer*4 maxa,bytesa,i
c      external getmd,freemd
c
      maxa=5
      bytesa=8
c
c Write Initial location.
c
      write(6,'(a)') 'Initial address'
c      write(6,*) ptr,maxa,bytesa
c
c Allocate real*8 array.
c
c       call getmd(ptr,maxa)
	ptr = malloc(maxa*8)
c
c Write addresses
c
      write(6,'(a)') 'Final address'
c      write(6,*) ptr,maxa,bytesa
c
c Work on array
c
      write(6,'(a)') 'REAL*8 array '
      if (ptr.ne.0) then
       	 do 10 i=1,maxa
           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
c      if (loc(a).ne.0) call freemd(a)
       if (ptr.ne.0) call free(ptr)
c
      stop
      end

Hope it helps,

- calvin
--
-----------------------------------------------------------------------------
Calvin H. Vu			   | "We are each of us angels with only one
Silicon Graphics Computer Systems  | wing.  And we can only fly embracing
calvin@sgi.com   (415) 962-3679	   | each other."