Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Fortran's analog to "void*" ?

1,374 views
Skip to first unread message

john.chl...@gmail.com

unread,
Oct 27, 2012, 4:34:48 AM10/27/12
to
If want a subroutine to have a dummy argument that is a "void" pointer and within the subroutine cast it as a pointer to something specific, how is this best accomplished?

---John

glen herrmannsfeldt

unread,
Oct 27, 2012, 4:50:36 AM10/27/12
to
I forget now if there is a real Fortran way to do it, other
than through the C interoperability feature.

Use type(c_ptr) for the dummy argument, and pass
the c_loc() of the actual argument.

If needed, you can C_F_POINTER to convert to a Fortran
pointer, but sometimes you don't need to do that.

As one example:


! sort using C qsort
use, intrinsic:: iso_C_binding
integer, target :: x(10)
data x/1,4,3,8,2,6,9,7,0,5/
interface
subroutine qsort(array,n,m,compar) bind(c)
use, intrinsic:: iso_C_binding
type(c_ptr), value :: array
integer(c_size_t) ,value:: m, n
type(c_funptr), value :: compar
end subroutine
integer(c_int) function icmp(a,b) bind(c)
use, intrinsic:: iso_C_binding
integer(c_int) :: a,b
end function
end interface
call qsort(c_loc(x),10_c_size_t ,c_sizeof(x(1)), c_funloc(icmp))
print *,x
end
!
integer(c_int) function icmp(a,b) bind(C)
use, intrinsic:: iso_C_binding
integer(c_int) :: a,b
if(a.gt.b) then
icmp=1
else if(a.lt.b) then
icmp=-1
else
icmp=0
endif
return
end

-- glen

jski

unread,
Oct 27, 2012, 5:11:03 AM10/27/12
to
On Oct 27, 4:50 am, glen herrmannsfeldt <g...@ugcs.caltech.edu> wrote:
I found this but it doesn't show how to specify a pointer as a "void"
pointer:

! The transfer intrinsic is Fortran 95's version of a void pointer.
! This program shows how to use transfer to encode a user-defined type
! in a character array.
program transfer_ex

implicit none

! A user-defined data type
type :: data_t
real :: x
end type data_t

! Data to be encoded
type(data_t), target :: d

! Encode data as an array of characters (one byte each)
character(len=1), dimension(:), allocatable :: enc
integer :: length

! Stash our data in d
d%x = 9.d0
print *, 'Data: ', d%x

! Encode the data_t object in a character array
length = size(transfer(d, enc))
allocate(enc(length))
enc = transfer(d, enc)
print *, 'Encoded: ', enc

! Decode again as data_t
d = transfer(enc, d)
print *, 'Decoded: ', d%x

! Clean up
deallocate(enc)

end program transfer_ex

Tobias Burnus

unread,
Oct 27, 2012, 6:04:00 AM10/27/12
to
john.chludzinski wrote:
> If want a subroutine to have a dummy argument that is a "void" pointer and within the subroutine cast it as a pointer to something specific, how is this best accomplished?


Well, the closed equivalent is Fortran TS 29113:2012, where one can do
the following (note the "TYPE(*)"). As the "2012" implies, that's a
brand new feature, which implies that no compiler has a complete support
for it.

! ----------------------------
implicit none

integer :: i
real :: r

i = 55
r = -42.0
call bar(i,1)
call bar(r,2)

contains
subroutine bar(x, j)
use iso_c_binding
type(*), target, intent(in) :: x
integer, value :: j

integer, pointer :: val_i
integer, pointer :: val_r

if (j == 1) then
call c_f_pointer (c_loc (x), val_i)
print *, 'Value i = ', i
elseif (j == 2) then
call c_f_pointer (c_loc (x), val_i)
print *, 'Value r = ', r
end if
end subroutine bar
end
! ----------------------------

$ gfortran foo.f90 && ./a.out
Value i = 55
Value r = -42.0000000


* * *

That feature requires gfortran 4.8 and there are still some issues with
assumed-rank arrays.


Another related feature is CLASS(*) of Fortran 2003. Even though the
year 2003 is a while back, it took (and takes) a while until compiler
have implemented that feature. gfortran presumably will get this feature
soon, but it hasn't yet. (Though, draft patches exist.)

The equivalent program like follows; it rather matches C++'s run-time
type system (RTTS) than C's (and C++'s) "void *":

! ----------------------------
implicit none

integer :: i
real :: r

i = 55
r = -42.0
call bar(i)
call bar(r)

contains
subroutine bar(x)
class(*) :: x

select type(x)
type is (integer)
print *, 'Value i = ', x
type is (real)
print *, 'Value r = ', x
end select
end subroutine bar
end
! ----------------------------


ftn -h cpu=x86-64 class_u_1.f90 && ./a.out
Value i = 55
Value r = -42.

* * *

Other possibilities are to handle the conversion in the caller not in
the callee. For instance, to convert everything to a "TYPE(C_PTR)", pass
it as C pointer, and convert it back via C_F_POINTER in the called
procedure. That's a Fortran 2003 possibility which is widely supported.

* * *

The fourth possibility is to use TRANSFER, which works since Fortran 90.
See Glen's email for an example.


It really depends on what you want to do with the passed data, i.e.
whether you just want to treat is as junk of (contiguous or
noncontiguous) bytes or whether you want to convert it back to something
else or �

In my opinion, if you just want to treat is a bytes ("void *buffer")
then TYPE(*) - possibly together with dimension(..) - is the best option
(and hence also used by the MPI 3 specification). Or for wider compiler
compatibility, TYPE(C_PTR) instead. If you want to convert it back,
CLASS(*) might be the best option. And for widest compiler
compatibility, TRANSFER is best as it already exists since Fortran 90.
But again, even my suggestion might be different, depending on the exact
use.

Tobias

Dick Hendrickson

unread,
Oct 27, 2012, 12:27:15 PM10/27/12
to
On 10/27/12 3:34 AM, john.chl...@gmail.com wrote:
> If want a subroutine to have a dummy argument that is a "void" pointer and within the subroutine cast it as a pointer to something specific, how is this best accomplished?
>
> ---John
Maybe I'm misunderstand this (you're using way too many C terms for me
;) ). But I think something like this is what you (should?) want

pointer :: xx, yy
nullify (xx)
or
yy => null()

Will set the association status of xx and yy to disassociated.

Then
call sub (xx)
or
call sub (yy)

to
subroutine sub (zz)
pointer :: zz

if (.not. associated(zz)) zz => whatever


I think the NULL() function and the NULLIFY statement more or less
correspond to setting a pointer to the C void status. The ASSOCIATED()
function lets you check for "void". As others ahve said, if you really
want to interoperate the pointers with C, it's harder. But, your
earlier questions have been oriented to translating C to Fortran.

Dick Hendrickson
0 new messages