views:

168

answers:

4

I have a C function

double* foofunc() {...}

I don't know how to declare the interface in Fortran to call to this C function.

The second question is: if this pointer is supposed to be pointing to GPU device memory. How could I define that in the Fortran interface, i.e. do I need to use DEVICE attribute.

Thanks, T.

Edit: Use any feature that Fortra support up to 2003

A: 

You want to call a C function from Fortran Program. There are many ways.

One way is to translate the C routine to fortran. If your C program is long, complex, and well tested then it may not be easy option for you. The other way is to convert the fortran to C. There may be similar problem to you.

If you can not skirt the problem as above, then you have to face the problem as below.

In programming parlance it is called Mixed Language Programming.

I do not know what version of which language and OS U are using. So instead of giving a ready made solution I shall give you four alternative approaches below. I have used all in implemented applications. The first two are for those lucky having a powerful OS ( a rare commodity now ). The program runs fast in both and suitable for hard real time jobs. The last two are for any OS, but program runs slow, particularly if C routine is called frequently. You also have to do little more programming work in all approaches. Be also aware that your C function returns a pointer in each of the alternatives.

  1. Some fortran compilers ( not all ) allow calling a non-fortran function. This requires appropriate facilities in the OS where both fortran and C are running. In such cases identical stack management is used during procedure call. Read the programmers manual of both languages and code appropriately.

  2. If this is not possible then you can trick the OS to do so but you need an intermediate function written in Assembler. You call assembler routine from fortran and then call the C routine from assembler and return in reverse manner. You need to know stack management details of all three that is of Fortran, Assembler and C and write a code for translating fortran stack to C stack. This will be in the assembler routine.

In both above approaches you have to be aware how your Linker ( or Binder ) works and you may have to do some extra job there. In either case it will be same .exe file so your program will run fast. In such OS’s any languages, strange to each other, can be mixed. Even DLL’s can be used. Only complexity comes if the run time library uses a fortran function having same name as a C function but doing different jobs. An OS supporting mixed language programming generally gives you some tools of preventing this.

  1. If above alternatives are not feasible, then make both fortran and C programs as separate .exe and run both as two concurrent processes. ( note they can be in same computer or in different computers under different OS even ! ). Now whenever you need to call C from fortran, pass all parameters and data though any interprocess communication mechanism available to you, say pipe, socket or whatever it is. The C program can return data by similar mechanism. Be sure to add appropriate code for handling parameter passing through interprocess communication. Synchronisation of two processes and distinguishing old data from recent data is also your job. Stack management is not required.

  2. This one is for those who dislike stack, synchronization, linker or anything that requires intelligence. Programs will run slowest if the C program has to be called frequently. Counter-intuitively, if the C program has to be called once only, then this becomes most intelligent solution too! Output data from fortran program to disk ( flat file or data-base ). Then call the C program to read from same file and return data to fortran in same manner. Be careful about closing the file before change of language. Handle all errors in file input-output calls. Else you crash.

nataraj bhattacharya
+1  A: 

Since you have Fortran 2003, the easy way to interface Fortran and C is to use the ISO C Binding. (Most Fortran 95 compilers now support the ISO C Binding, even if they aren't full Fortran 2003 compilers.) This is far, far better than the complicated methods suggested in an earlier answer, which were necessary in an earlier era -- it is part of the language and therefore portable, and compiler and platform independent. But the Fortran 2003 version doesn't cover ever possibility. (The next Fortran will add additional cases of interfacing to C.) You can easily pass an argument that is a C pointer -- just leave off the "value" atttribute in the Fortran declaration. A pointer to a pointer needs C_PTR. I don't know about a pointer as a function return... I will have to experiment when I have time. If you have to, make a trivial C glue routine that converts the pointer of the function return into an argument -- that case is easy.

Re a pointer to GPU device memory -- unless your compiler has a non-standard feature, it won't have "DEVICE". Perhaps "volatile" will help? Create an appropriate user-defined type...

There are examples in the gfortran manual under "Interoperability with C". Since this is part of the language, this documentation should help even if you aren't using gfortran.

M. S. B.
+1  A: 

Your answer is same as point no - 1 of my answer ( 1.Some fortran compilers ... ). You however mentioned that "But the Fortran 2003 version doesn't cover every possibility". This is a practical point.

Programmers often meet the target; come whatever may be the problem, even if latest version of compiler or connector is not available. I have given field tested alternatives. There is one alternative for school students and another for "hard real time" problems. It may take longer time, but what to do until you get a version of Fortran that perfectly interfaces with another language.

If your existing debugged fortran and C programs together are 30,000 lines long, then using a new version of compiler in a 2000 client system may unmask a host of other problems. People have lost more time with such issues than working a few extra man-days to write some connectors himself using commonly available resources in existing compiler and OS. We implement the new compiler after fresh testing of all components of our applications. The golden rule is “it is easier to work with an existing compiler with its known bugs, than working with its latest version having unknown bugs”. The rule is applicable only for large practical problems.

nataraj bhattacharya
A: 

As M. S. B. said, using the fortran 2003 C interoperability features is easiest.
Simply declare the function result as type(c_ptr), and transform it to a fortran pointer by calling c_f_pointer.

The following simple example works when compiled with:
gfortran foo.f03 foofunc.c -o foo.exe
(gfortran version 4.5.0)

Contents of foo.f03:

program foo
  use, intrinsic :: iso_c_binding, only : c_ptr,        &
                                          c_f_pointer,  &
                                          c_double
  implicit none
  type(c_ptr) :: c_p
  real(c_double), pointer :: f_p

  interface
    function foofunc() bind(c)
      import :: c_ptr
      implicit none
      type(c_ptr) :: foofunc
    end function foofunc
  end interface

  c_p = foofunc()
  call c_f_pointer(c_p, f_p)
  print *, f_p
end program foo

Contents of foofunc.c:

double bar = 2;

double *foofunc()
{
  return &bar;
}

I don't know how well it will work with a pointer to GPU device memory, though. Never dealt with that.

eriktous