(j3.2006) Questions and ideas about writing bind(c) interfaces

Rafik Zurob rzurob
Sat Sep 26 12:46:41 EDT 2015


Hello

I've been writing a few interfaces for BIND(C) functions lately, and have 
run into a few scenarios that are hard to express in standard Fortran 
without using wrappers.

1. Conversion of actual arguments corresponding to by-value dummy 
arguments of a "wider" kind.

If we have a by-value dummy argument of type c_size_t, it's currently not 
allowed to have a corresponding actual argument of type c_int.  As a 
result, users have to convert, either by using temps, INT(), or specifying 
the kind of literals.  I think the most common example is malloc:

subroutine foo(num_bytes)
use, intrinsic :: iso_c_binding, only: c_ptr, c_int, c_size_t
implicit none
integer(c_int) num_bytes

interface
  function malloc(x) bind(c, name='malloc')
    import c_ptr, c_size_t
    implicit none
    integer(c_size_t), value :: x
    type(c_ptr) malloc
  end function
end interface

type(c_ptr) p
p = malloc(16)  ! Error.  Needs to be malloc(16_c_size_t)
p = malloc(num_bytes) ! Error.  Need to create temp, or use INT() to 
convert.
!...
end

In C/C++, the equivalent actual arguments are automatically converted to 
the wider type without error.  (Note that this statement is only about 
widening conversions, not narrowing conversions.)

I'm trying to understand why Fortran doesn't allow this.  One thought I 
had is that automatic conversion would have an impact on generic interface 
ambiguity and generic resolution, so it would not be backwards compatible 
with Fortran 2003.  But that does not explain why it was done this way in 
Fortran 2003 in the first place.


2. By-reference TYPE(*) vs by-value C_PTR
Say I want to write a Fortran interface for the following C function:
void foo(void *x);

I could write:

interface
  subroutine foo(x) bind(c, name='foo')
    type(*) x(*)
  end subroutine
end interface

but some users might already have the address they want to pass in a C_PTR 
variable.  Furthermore, they might no longer have access to the original 
variable that the C_PTR came from.  For example, in my malloc example 
above, malloc returns a C_PTR that is store in variable "p".  Passing "p" 
to foo would pass the address of "p" not the value of "p".  So this 
use-case would need an interface like this:

interface
  subroutine foo(x) bind(c, name='foo')
    use iso_c_binding, only: c_ptr
    type(c_ptr), value :: x
  end subroutine
end interface

The problem is that the two interfaces can't co-exist in the same scoping 
unit.  It would have been nice to have been able to just pass a C_PTR 
actual argument to a function expecting a type(*) dummy argument and have 
that mean that the value of the C_PTR is passed instead of the address. Of 
course, had we done that, I would be asking how to send an 
address-to-address from Fortran to C.  Was this issue considered during 
the development of TS29113?


3. No way to describe "const int *" in Fortran interfaces using C_PTR
"const int *" in C means that the target of the pointer can't change, but 
the pointer itself can.  If I want to write an interface for
void foo(const int *x);
using C_PTR, I have to write:

interface
  subroutine foo(x) bind(c, name='foo')
    use iso_c_binding, only: c_ptr
    type(c_ptr), value :: x
  end subroutine
end interface

but this interface does not express that the target of the C_PTR cannot 
change.  It would be nice if iso_c_binding provided a const_c_ptr type and 
a conversion function to convert from const_c_ptr to c_ptr.  Passing a 
const_c_ptr actual argument to a procedure with a corresponding c_ptr 
dummy argument would be disallowed.  Assignment from c_ptr to const_c_ptr 
would automatically convert the c_ptr to const_c_ptr.  Similarly, passing 
a c_ptr actual argument to a procedure with a corresponding const_c_ptr 
dummy would involve automatically converting the c_ptr into const_c_ptr.

Regards

Rafik




More information about the J3 mailing list