Search code examples
cfortranfortran90gfortranintel-fortran

Absent parameters in C function called from Fortran


I am working with Fortran 90 code that calls a C function. This code is well tested and compiles successfully with the Intel Fortran compiler. I'm trying to get it to work with the GNU Fortran compiler. The F90 code calls a C function, but it does not specify some of the parameters. The call looks like this:

call c_func_name(1, n, q, , , , p)

which evidently works fine with ifort, but not with gfortran, which fails with the error

Error: Syntax error in argument list at (1)

where 1 is at the comma following the first blank argument. I cannot find any information about what is going on here. Is this an Intel compiler specific syntax for passing dummy arguments? If so, can someone point me to a reference?


Solution

  • Ifort actually passes the NULL pointer for the not specified arguments. Compiling and linking the Fortran program

    program test
      implicit none
    
      call c_func(1, ,3)
    
    end program test
    

    and the corresponding C-function

    #include <stdio.h>
    
    void c_func_(void *p1, void *p2, void *p3)
    {
      printf("P1: %p\nP2: %p\nP3: %p\n", p1, p2, p3);
    }
    

    you would obtain:

    P1: 0x4729f4
    P2: (nil)
    P3: 0x4729f0
    

    This behaviour is, however, definitely an extension to the standard. By giving the C function an explicit interface in Fortran, you can "emulate" it with any compilers, implementing the C-binding features of the Fortran 2003 standard. You would have to pass the C_NULL_PTR constant for the given parameter.

    In the Fortran program below, I created an explicit interface for the C-function. In that example Fortran would pass a pointer to an integer, an arbitrary C-pointer and again a pointer to an integer.

    program test
      use iso_c_binding
      implicit none
    
      interface
        subroutine c_func(p1, p2, p3) bind(c, name='c_func')
          import
          integer(c_int) :: p1
          type(c_ptr), value :: p2
          integer(c_int) :: p3
        end subroutine c_func
      end interface
    
      type(c_ptr) :: cptr
    
      call c_func(1, C_NULL_PTR, 3)
    
    end program test
    

    Since I used an explicit name in the bind(c) option, the name of the function in the C-code does not need to contain any magic, compiler dependent trailing underscores any more. I also changed the pointer types on the C-side to the corresponding types:

    #include <stdio.h>
    
    void c_func(int *p1, void *p2, int *p3)
    {
      printf("P1: %p\nP2: %p\nP3: %p\n", p1, p2, p3);
    }
    

    Compiling and linking the two componentes with gfortran (I used 4.7.2) and executing the resulting binary results in:

    P1: 0x400804
    P2: (nil)
    P3: 0x400800