(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