Fortran 2008 C interop Error: More actual than formal arguments in procedure call at (1)

4.2k Views Asked by At

I have this specific and on-topic question that was closed, trying to call C from the libcurl simple API from Fortran: https://stackoverflow.com/questions/44891188/calling-libcurl-from-fortran-2008

Following advice from the comments, I am still getting errors about how to correctly call the C pointers and C functions from Fortran.

Not much code here, but main problems are warnings:

dl2.f08:11.23:

  type, bind(C) :: CURL
                       1
Warning: Derived type 'curl' with BIND(C) attribute at (1) is empty, and may be inaccessible by the C companion processor
dl2.f08:14.27:

And errors:

  call curl_easy_setopt(curl, CURLOPT_URL_VAL, "http://example.com")
                                                                    1
Error: More actual than formal arguments in procedure call at (1)
dl2.f08:48.35:

Here is my minimal example:

module fcurl
! This is the simple C code I am trying to call from Fortran
!
! CURL *curl = curl_easy_init();
! if(curl) {
!   CURLcode res;
!   curl_easy_setopt(curl, CURLOPT_URL, "http://example.com");
!   res = curl_easy_perform(curl);
!   curl_easy_cleanup(curl);
! }
  use, intrinsic ::  iso_c_binding
  implicit none
  type, bind(C) :: CURL
  end type CURL

  type, bind(C) :: CURLcode
  end type CURLcode

  type, bind(C) :: CURLOPT_URL
  end type CURLOPT_URL

  interface
     subroutine curl_easy_init()  bind(C, name="curl_easy_init")
     end subroutine curl_easy_init
  end interface

  interface
     subroutine curl_easy_setopt()  bind(C, name="curl_easy_setopt")  
     end subroutine curl_easy_setopt
  end interface

  interface
     subroutine curl_easy_perform()  bind(C, name="curl_easy_perform")  
     end subroutine curl_easy_perform
  end interface

  interface
     subroutine curl_easy_cleanup()  bind(C, name="curl_easy_cleanup")  
     end subroutine curl_easy_cleanup
  end interface  

end module fcurl

program mycurl
  use fcurl
  type(CURL) :: curl
  type(CURLcode) :: res
  type(CURLOPT_URL) :: CURLOPT_URL_VAL
  call curl_easy_init(curl)
  call curl_easy_setopt(curl, CURLOPT_URL_VAL, "http://example.com")
  call curl_easy_perform(res, curl)
  print *, res  
  call curl_easy_cleanup(curl)

end program mycurl

Also referenced this:

1

There are 1 best solutions below

0
On

I want just clarify somethings about C inter-portability:

  1. To make a type inter-portable you should retype its definition in Fortran with the keywork bind(c), Example:

    The type type_c defined in C as:

    struct {
      int i;
      double d
    } type_c;
    

    in Fortran, we should write it as:

    type ,bind(c) :: type_c
      integer(c_int) :: i
      real(c_double) :: d
    end type
    
  2. In Fortran there are two types of procedures : functions and subroutines. the equivalent of subroutines in C are functions declared with void ( in C: it means function that doesn't return a value).So, to make the C procedures inter-portable you should firstly look at their definitions and decide if it is equivalent to a Fortran function or a subroutine.
  3. To make C procedures inter-portable with Fortran you should define them with their arguments, for example:

    The functions 'fun1' and 'fun2' are defined in C as:

    float fun1(int i);
    void fun2(double a, int *l);
    

    in Fortran we should write them as:

    interface
      function fun1(i) bind(c)
        real(c_float) :: fun1
        integer(c_int), value :: i
      end function fun1
    end interface
    
    interface
      subroutine fun2(a,l) bind(c)
        real(c_double), value :: a
        integer(c_int) :: l
      end subroutine fun2
    end interface