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

Pointer and target, same LOC?

MWind2
New Contributor III
1,563 Views

I want to ask why, but I should know better:

 INTEGER, VOLATILE, TARGET :: I1 = 2
    INTEGER, POINTER :: PI1
    INTEGER :: I2= 8
    ! Body of Interlocked
    PI1=>I1
    if (loc(PI1) == loc(I1))  print *, "true"

 

prints true? 

0 Kudos
9 Replies
IanH
Honored Contributor III
1,563 Views

LOC is an Intel (and others) extension, so consult the Intel documentation for the expected behaviour. That documentation defines LOC such that for pointer arguments, you get the address of the associated target. 

This is consistent with how pointers in Fortran work, outside of a pointer association context you work on or with the target of the pointer.

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,563 Views

>>outside of a pointer association context you work on or with the target of the pointer

For illustration, consider:

real, allocatable :: Array
integer(C_PTR) :: locArray
...
allocate(Array(1234))
...
locArray = LOC(Array)

The intention is to return the address of the first cell of the array as opposed to the location of the array descriptor that references Array.

If you really need the address of the pointer, that would be the subject of a different matter.

Jim Dempsey

0 Kudos
MWind2
New Contributor III
1,563 Views

Thanks and to me both answers are best. There is another closed post about dereferncing c_ptrs, https://software.intel.com/en-us/forums/intel-visual-fortran-compiler-for-windows/topic/282809 from 2011, and I wonder if anything has changed since then?  Assuming Fortran type is known and if array,length, then use  CALL C_F_POINTER(PCI1, PFI1 [,shape])?

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,563 Views

FWIW

If the Fortran pointer is that to a scalar or to a user defined type (NOT an array) and you wish for the pointer itself to be interlocked... the make a user defined type containing only that pointer

type foo_t
   ...
end type foo_t

type p_foo_t
  type(foo_t), pointer :: p
end type p_foo_t
...
type node_t
  type(p_foo_t) :: next
  type(foo_t) :: foo
end type node_t

...
a_node => someNode
...
...(LOC(a_node%next), ...  ! address of the pointer a_node%next%p

Jim Dempsey

0 Kudos
MWind2
New Contributor III
1,563 Views

I will  be playing with that for a while....

0 Kudos
Steve_Lionel
Honored Contributor III
1,563 Views

The confusion here is that a pointer in Fortran is not like a pointer in C. When you "reference" a pointer, you're referencing its target. There is no good way in Fortran to get the address of the pointer itself.

0 Kudos
FortranFan
Honored Contributor III
1,563 Views

jimdempseyatthecove (Blackbelt) wrote:

FWIW

If the Fortran pointer is that to a scalar or to a user defined type (NOT an array) and you wish for the pointer itself to be interlocked... the make a user defined type containing only that pointer ..

Jim,

Fortran standard effectively makes a derived type available for this: C_PTR in the intrinsic ISO_C_BINDING.

I'm not exactly sure what is of interest to OP but using the standard facilities in Fortran rather than any compiler vendor-specific extensions and viewing an object in Fortran with the POINTER attribute as ephemeral but working with the derived type C_PTR for whatever needs there may be for OP may be the better option:

   use, intrinsic :: iso_c_binding, only : c_long, c_ptr, c_loc, c_intptr_t, c_f_pointer

   interface
      function InterlockedExchangeAdd(Addend,Value) result(r) bind(C, name="InterlockedExchangeAdd")
      !DIR$ ATTRIBUTES STDCALL :: InterlockedExchangeAdd

      ! MSDN function prototype:
      ! https://docs.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-interlockedexchangeadd
      ! LONG InterlockedExchangeAdd(
      !   LONG volatile *Addend,
      !   LONG          Value
      !);
         import :: c_long
         implicit none
         ! Argument list
         integer(c_long), volatile, intent(inout) :: Addend
         integer(c_long), value, intent(in)       :: Value
         ! Function result
         integer(c_long) :: r
      end function
   end interface

   ! Local variables
   integer(c_long) :: I0 = 1
   integer(c_long), volatile, target :: I1 = 2
   integer(c_long) :: I2 = 42

   I0 = InterlockedExchangeAdd(I1, I2)

   print *, "I0 = ", I0

   blk_loc: block

      ! type(c_ptr) as 'proxy' for integer, pointer
      type(c_ptr) :: PI1
      integer(c_long), pointer :: ptrI1 => null()
      integer(c_intptr_t) :: add_ptrI1

      PI1 = c_loc(I1)

      call c_f_pointer( PI1, fptr=ptrI1 )
      print *, "PI1 = ", ptrI1, "; expected is ", I0+I2
      ptrI1 => null() ! view ptrI1 as ephemeral; work with type(c_ptr) :: PI1 instead
      print *, "Address of PI1 = ", transfer( source=c_loc(PI1), mold=add_ptrI1 )

   end block blk_loc

   stop

end

Upon execution,

C:\Temp>ifort /standard-semantics /warn:all /stand:f18 p.f90
Intel(R) Visual Fortran Intel(R) 64 Compiler for applications running on IA-32, Version 19.1.0.085 Pre-Release Beta Build 20190522
Copyright (C) 1985-2019 Intel Corporation.  All rights reserved.

ifort: NOTE: The Beta evaluation period for this product ends on 9-oct-2019 UTC.
p.f90(5): warning #7025: This directive is not standard F2018.
      !DIR$ ATTRIBUTES STDCALL :: InterlockedExchangeAdd
------------^
Microsoft (R) Incremental Linker Version 14.21.27702.2
Copyright (C) Microsoft Corporation.  All rights reserved.

-out:p.exe
-subsystem:console
p.obj

C:\Temp>p.exe
 I0 =  2
 PI1 =  44 ; expected is  44
 Address of PI1 =  18348584

C:\Temp>

 

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,563 Views

The OP desired for the use of an INTEGER, POINTER as the argument of InterlockedExchangeAdd

Using INTEGER(C_PTR) makes the named pointer unusable for use by the Fortran code (statements) as a pointer.

This results in the programmer being required to do some hoop jumping in order to use the Addend of the InterlockedExchangeAdd as a Fortran pointer to integer. The user defined type does this cleanly with the expense of node%nexr%p in the user code. This would be a user preference.

BTW EQUIVALENCE would handle this nicely too.

Jim Dempsey

0 Kudos
FortranFan
Honored Contributor III
1,563 Views

jimdempseyatthecove (Blackbelt) wrote:

The OP desired for the use of an INTEGER, POINTER as the argument of InterlockedExchangeAdd

Using INTEGER(C_PTR) makes the named pointer unusable for use by the Fortran code (statements) as a pointer.

This results in the programmer being required to do some hoop jumping in order to use the Addend of the InterlockedExchangeAdd as a Fortran pointer to integer ..

OP (and any other reader) wanting to perform atomic operations using Windows OS kernel functions can try to use standard Fortran facilities for the interoperation instead of Intel-supplied non-standard compiler-specific options and thus bypass the need to use LOC in the first place and not have to deal with the addresses of objects ..

0 Kudos
Reply