Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28440 Discussions

Integer pointers for allocatable objects

mamey4
Beginner
757 Views
Hi,

I'm working on a code right now where an integer pointer is created in the following way:

pointer (bufptr,buffer)

Now this does not work if buffer is an allocatable object; this is expected behaviour from what I understand. Is there a way to circumvent this, meaning to create an integer pointer to an allocatable object?
I tried to do a workaround with C pointers and iso_c_binding, like:

type(c_ptr) cptr
allocate(buffer(1024))
cptr=c_loc(buffer)
call c_f_pointer(cptr,bufptr)

But this creates a "Fortran pointer", which is not what I need.

mamey
0 Kudos
11 Replies
Arjen_Markus
Honored Contributor I
757 Views

If you want a pointer to the array buffer, why not simply:

integer, dimension(:), pointer :: bufptr
integer, dimension(:), allocatable, target :: buffer

allocate( buffer(1024) )
bufptr => buffer

I may misunderstand your question, but then explain why a Fortran pointer does not work for you?

Regards,

Arjen

0 Kudos
mamey4
Beginner
757 Views
A Fortran pointer does not work for me, because later in the program I need the pointer to interact with some Win32 API routines, which do not return "Fortran pointers", but "integer pointers". It basically looks like this:


program main
...
integer :: bufptr, buffer(1024)
pointer (bufptr,buffer)
...
call fct1(bufptr)
...
end program main


subroutine fct1(bufptr)
...
integer, intent(out) :: bufptr
integer :: ptr1,trg1
pointer(ptr1,trg1)
...
ptr1=Win32APIFunction(...)
bufptr=ptr1
...
return
end subroutine

0 Kudos
Steven_L_Intel1
Employee
757 Views
Since you're already using one extension, just assign LOC(allocatable-var) to your integer pointer. Or use the intrinsic malloc to allocate space and assign the address to your integer pointer.

You can also use TRANSFER to "cast" a C_PTR to an integer pointer or address being passed to a Win32 API routine.
0 Kudos
mamey4
Beginner
757 Views
I tried to replace my original code

integer :: bufptr, buffer(1024)
pointer (bufptr,buffer)

both with

integer(C_INTPTR_T) :: bufptr
integer, allocatable :: buffer(:)
type(c_ptr) cptr
allocate(buffer(1024))
cptr=c_loc(buffer)
bufptr=transfer(cptr,bufptr)

and

integer :: bufptr
integer, allocatable :: buffer(:)
allocate(buffer(1024))
bufptr=loc(buffer)

but only the first option works for my program. I guess the problem could be the nature of the API function I call; it's called CreateFileMapping(), and I use it for interprocess communication. Actually I'm rewriting an IPC example I found on the net: http://www.fortranlib.com/ShareBufferWin32.f90 - but in the example only statically allocated shared memory parts are used.


0 Kudos
Steven_L_Intel1
Employee
757 Views
Are you building for 64-bits? If so, the second code is wrong. Replace the first line with:

integer(int_ptr_kind()) :: bufptr

or

integer(C_INTPTR_T) :: bufptr
0 Kudos
mamey4
Beginner
757 Views
I'm not building for 64bits, but I still tried your suggestion - no improvement.
I must say I'm a little bit confused about the different possibilities of using Cray pointers ("integer pointers" and "C_PTR's") - what's the difference between them, and are they generally not able to point to a dynamically allocated piece of memory, or why else is it forbidden in the pointer(x,y) statement for y to be allocatable? I think if I knew the (technical) reason for this, it could be easier to find out why using C_PTR does not work.
0 Kudos
IanH
Honored Contributor II
757 Views
The difference is mostly syntactic - the internal representation of the C_PTR and the integer pointer will be the same (it is a memory address). C_PTR and the other C interoperability stuff is in the F2003 standard, so it may be more portable. The Intel provided interfaces to the windows API pre-date this stuff - so they use the integer (Cray) pointer approach. I suspect that if you were implementing the interfaces from scratch today you'd just stick with the F2003 compliant approach (but you still have an issue with the API calling convention on x86, pity there's not a BIND(_STDCALL) or similar that the windows vendors agree to).

POINTER(x,y) with y allocatable would imply that you are specifying where in memory an allocatable variable must be allocated. That's not really a consistent concept - for example if you knew the address of some memory was available for use then you wouldn't need to allocate it in the first place.

If you want to know where the storage for an allocated variable is (you have a variable, you want to know its address) then use the LOC (or C_LOC for a C_PTR) functions. If you want to treat the memory at some address as some particular type of variable (the other direction - known as de-referencing) then use the POINTER statement (or the C_F_POINTER procedure for C_PTR's).

Which windows API's are you calling? Can you show more code? Your API calling example showed an API that returned a pointer - how would that relate to an allocatable variable?
0 Kudos
mamey4
Beginner
757 Views
Ok, that makes things a little bit more clear.
What I basically want to implement is the example shown here: http://www.fortranlib.com/ShareBufferWin32.f90 - a shared buffer communication between two individual programs. This works fine for a buffer of fixed size (as shown in the example with buffer(1024)). I'd like to know if it's possible to do the same kind of data exchange between the programs with the shared buffer being of variable size, which could be determined by the two programs (of course consistently) before the shared buffer communication is established.
0 Kudos
Steven_L_Intel1
Employee
757 Views
The biggest difference between Cray pointers and C_PTR is that C_PTR is an "opaque type" - it is a derived type whose contents you don't have direct access to. You can't do much with a C_PTR by itself other than pass it as an argument, though you can TRANSFER it to a pointer-sized integer.

Cray (integer) pointers are a different feature where there are two variables, one an integer holding the address and the other a "virtual" variable that has no storage of its own. The pointee in a Cray pointer cannot be allocatable because the whole idea is that the address is in the other pointer variable.

Both kinds can point to dynamic memory. In general I recommend using standard features where available rather than extensions.
0 Kudos
mfinnis
New Contributor II
757 Views
I haven't looked at the example quoted above but this is an example that answers your original question:

[fortran]  program APTest

  integer :: i

  integer(2), allocatable :: my_buffer(:)

  integer(2) :: i_words
  pointer (iwptr,i_words(*))

  integer(1) :: i_bytes
  pointer (ibptr,i_bytes(*))

  allocate(my_buffer(0:1023))

  do  i = 0,Size(my_buffer) - 1
      my_buffer(i) = i
  end do 

  iwptr = Loc(my_buffer)
  ibptr = Loc(my_buffer)  

  do  i = 512,524
      write(*,*) i_words(i)
  end do      

  do  i = 512,524
      write(*,*) i_bytes(2*i + 1),i_bytes(2*i + 2)
  end do

  end program APTest

[/fortran]


0 Kudos
mamey4
Beginner
757 Views
I guess this gives the correct result, although I don't quite understand how; when printing the integer pointer's value and the loc() of my buffer it gives me the same output. I guess then there must be some problem with the FileMapping-API, but figuring this out probably goes beyond the topic of this thread.
0 Kudos
Reply