example Fortran interoperate with C

Hi,
Could someone provide an example of using Fortran 2003 to call a C function.

Thanks,
Tuan

Hi Tuan,

Here’s one of our internal test codes which shows how to use “bind©” in an interface block to tell Fortran that you’re calling a C routine. I don’t show all the ISO_C_BINDING data types, but they are all fully supported.

bind.f90

    module test

       integer N
       parameter (  N = 28)
       integer ND
       parameter (  ND= 4 )

      interface
	subroutine plainc (a,b,c) bind(c, name = 'newc')
	integer a,b
	real c
	end  subroutine plainc 
	
	subroutine intfunc (a,b,c,d,e,f,g,h,i) bind(c)
        integer, value :: a,b,c,d,e,f,g,h
        integer *8, value :: i
        end subroutine intfunc

	subroutine logfunc (a,b,c,d,e,f,g,h) bind(c)
        integer  , value :: a,b,c,d
        logical , value :: e,f,g,h
        end subroutine logfunc

	function realfunc (a,b,c,d,e,f,g,h,i) result(bind) bind(c)
        real, value :: a,b,c,e,f,g,h
        real *8, value :: i,d
	integer bind
        end function realfunc


	subroutine check (a,b,c) bind (c)
	integer a(N), b(N), c
        end subroutine check

	subroutine checkd (a,b,c) bind (c)
	real*8 :: a(ND), b(ND)
        integer :: c
        end subroutine checkd

      end interface



   common /result/ a_array
   integer a_array(N)
   BIND (c) ::/result/

   common /expect/ e_array
   integer e_array(N)
   BIND (c) ::/expect/


   common /d_expect/ d_array
   real *8 d_array(ND)
   BIND (c) ::/d_expect/

   common /d_result/ dr_array
   real *8 dr_array(ND)
   BIND (c) ::/d_result/


   end module

	use test
	logical ll
	real*8 tt
	real bind

      integer*8 kko
      kko = 45
	ll = .FALSE.
	tt = 50.0

       call plainc (1,2,4.0)
       call intfunc(3,4,5,6,10,20,30,40,kko)
       call logfunc(7,8,9,10,.TRUE., .FALSE., .TRUE. , .FALSE. )
       a_array(25) = realfunc(2.0, 3.0, 4.0, tt,3.0,3.0,6.0,30.03E04,400.004D01)
       call check(a_array, e_array , N)
       call checkd(dr_array, d_array, ND)
      end

bindc.c

/* C counterpart to test Fortran BIND(C) functions, 
   subroutines
 */

#include <stdio.h>

#define N 28
#define ND 4


extern int expect[N]= {  /* newc */ 
			0, 1, 2, 4,
			/* intfunc */
			3, 4, 5, 6, 10, 20, 30, 40, 45,
			/* logfunc */
			7, 8, 9, 10, -1, 0, -1, 0,
			/* real func */
			2.0, 3.0, 4.0,      22 ,        3.0,
			3.0, 6.0 };
			
extern  double d_expect[ND]= { /* realfunc */
			 0.0, 300300.0, 4000.04, 50.0};
int result[N];
double d_result[ND];



void newc (int *a, int *b, float * kk) {


result[0] = 0;
result[1] = *a;
result[2] = *b;
result[3] = *kk;

}


void intfunc( int a, int b, int c, int d, char i1, 
		     short i2, int i3, int i4, long long i8) {

result[4] = a;
result[5] = b;
result[6] = c;
result[7] = d;
result[8] = (int) i1;
result[9] = (int) i2;
result[10] = i3;
result[11] = i4;
result[12] = (int) i8;

}

void  logfunc( int a, int b, int c, int d, 
		     int i2, int i3, int i4, int i8) {
result[13] = a;
result[14] = b;
result[15] = c;
result[16] = d;
result[17] = i2;
result[18] = i3;
result[19] = i4;
result[20] = i8;

}

int  realfunc( float a, float b, float c, double d, 
		     float e, float f, float g,
		     float r4, double r8) {

result[21] = a;
result[22] = b;
result[23] = c;
result[24] = 0; /* f90 will store return val */
result[25] = e;
result[26] = f;
result[27] = g;
d_result[0] = 0.0;
d_result[1] = r4;
d_result[2] = r8;
d_result[3] = d;
return (22);

}
 

void
check(res, exp, np)
    int *res, *exp, *np;
{
    int i;
    int n = *np;
    int tests_passed = 0;
    int tests_failed = 0;

    for (i = 0; i < n; i++) {
        if (exp[i] == res[i]) {
	    tests_passed ++;
        } else {
            tests_failed ++;
            printf(
	    "test number %d FAILED. res %d(%08x)  exp %d(%08x)\n",
	     i+1,res[i], res[i], exp[i], exp[i] );
        }
    }
    if (tests_failed == 0) {
	    printf(
	"%3d tests completed. %d tests PASSED. %d tests failed.\n",
                      n, tests_passed, tests_failed);
    } else {
	printf("%3d tests completed. %d tests passed. %d tests FAILED.\n",
                      n, tests_passed, tests_failed);
    }
}

void
checkd(res, exp, np)
    double *res, *exp;
    int *np;
{
    int i;
    int n = *np;
    int tests_passed = 0;
    int tests_failed = 0;

    for (i = 0; i < n; i++) {
        if (exp[i] == res[i])  tests_passed ++;
        else {
            int j = (res[i] - exp[i]) * 1000.0;
            tests_failed ++;
            printf("test number %d FAILED. double prec diff: %d\n",
                      i+1, j/*,  res[i], exp[i] */ );
        }
    }
    if (tests_failed == 0) {
	    printf(
	"%3d tests completed. %d tests PASSED. %d tests failed.\n",
                      n, tests_passed, tests_failed);
    } else {
	printf("%3d tests completed. %d tests passed. %d tests FAILED.\n",
                      n, tests_passed, tests_failed);
    }
}



% pgfortran -fast bind.f90 bindc.c -o bind.out
bind.f90:
bindc.c:
% bind.out
 28 tests completed. 28 tests PASSED. 0 tests failed.
  4 tests completed. 4 tests PASSED. 0 tests failed.

Hope this helps,
Mat

Thanks Mat, appreciate that.

One question: how do I know the list of all C types that PGI Fortran currently supports with an interoperable type and kind parameter.
E.g.: I want to known the Fortran interoperable type with uint64_t in C. The book Fortran 95/2003 only mention int64_t.

Tuan

Hi Tuan,

E.g.: I want to known the Fortran interoperable type with uint64_t in C. The book Fortran 95/2003 only mention int64_t.

We support the standard which does not include unsigned types. You’ll need to use “C_INT64_T”. Though, this should be ok given how big of an integer you’d need to overflow into the negative values.

  • Mat

Thanks, Mat.
Tuan