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

Equivalencing and Pointer Arrays

John6
Beginner
1,014 Views

I currently have a rank one array tb which is equivalenced to a rank four array ta(81,81,3,2).

The subsequent code uses tb exclusively (not ta), and the indexing into tb is variable.

So, I can access ta data using tb(i), where i is any integer from 1 to 81*81*3*2 = 39366 without experiencing any run time out-of-bounds errors.

What I would like to do is remove the equivalencing and somehow change tb to a pointer array, so that I can use the same indexing tb(i) as before.

So I changed tb to a rank 1 pointer array with the statement Real, Pointer :: tb(:)

Then I pointed to the rank 4 array using tb => ta(:,1,1,1)

The end result of this is that with the "Check Array Bounds" option on, the compiler (correctly) flags the over-bounds error at run-time when tb accesses ta with a subscript greater than 81.

However, when I turn the "Check Array Bounds" off, the program works perfectly, and gives me the correct answer.

The problem is, I like the array bounds checking and I would like to keep it on if possible.

My question is: Is there a better way to remove the equivalencing (using pointer arrays, perhaps?) and if so, can someone provide an example?

0 Kudos
12 Replies
IanH
Honored Contributor III
1,014 Views
You could roll your own equivalencing using C interoperability.

USE ISO_C_BINDING

REAL(C_FLOAT), TARGET :: rank_four(na,nb,nc,nd)
TYPE(C_PTR) :: intermediate_c_ptr
REAL(C_FLOAT), POINTER :: rank_one(:)
...
intermediate_c_ptr = C_LOC(rank_four)
CALL C_F_POINTER(intermediate_c_ptr, rank_one, [ SIZE(rank_four) ])


0 Kudos
Steven_L_Intel1
Employee
1,014 Views
Beat me to it. You don't need the intermediate pointer - just pass C_LOC(rank_four) as the first argument to C_F_POINTER.

I'll comment that Intel Fortran does now support bounds remapping of pointers, but that won't let you change the rank.
0 Kudos
John6
Beginner
1,014 Views

I'm not too familiar with ISO_C_BINDING.
Would "Use ISO_C_BINDING" be platform compatible (Win-OS and Linux)?
Is there any way to do it without using the "Use" statement?
Can you provide a small example of "bounds remapping of pointers"?

0 Kudos
John6
Beginner
1,014 Views

Use ISO_C_BINDING seems to result in:

error #6285: There is no matching specific subroutine for this generic subroutine call. [C_F_POINTER]

0 Kudos
anthonyrichards
New Contributor III
1,014 Views
I was recommended to use

USE , INTRINSIC :: ISO_C_BINDING

which is a different module.
0 Kudos
John6
Beginner
1,014 Views
Yes, I tried that too (it was specified that way in the help), but I got the same message.
0 Kudos
Steven_L_Intel1
Employee
1,014 Views
Unless you have your own ISO_C_BINDING, either way should work. But USE,INTRINSIC is preferable.

John, can you show us your test source?
0 Kudos
John6
Beginner
1,014 Views
Yes, that did work after all.

I had made the mistake of putting in a const int for the third argument on the call, which is what caused the error message :

CALL C_F_POINTER(C_LOC(ta), tb, 1) caused the error,

whereas

CALL C_F_POINTER(C_LOC(ta), tb, [SIZE(ta)]) did not.

So, this is one option and turning off the array bounds checking is one option.

Is there any option which could work with array bounds checking on but without using the ISO_C_BINDING?
0 Kudos
Steven_L_Intel1
Employee
1,014 Views
You certainly would not want 1 for the last argument. This argument is the new shape of the Fortran pointer, and it is an array of upper bounds. You could have used [1] to make an array with one element consisting of 1, but that's not what you want.

Why not use ISO_C_BINDING? This is standard Fortran. I can't think offhand of another method that would work that isn't an extension.
0 Kudos
John6
Beginner
1,014 Views

My only reason is platform and compiler compatibility. Although currently we use Intel's Fortran compiler on both Windows and Linux OS, we also have HP compilers on some of our older machines, and I am not entirely sure that some of the compilers we have support Fortran beyond F77. Plus, we sometimes have to work with customers who use gfortran, which I'm not sure of either. So I have been hesitant at times tomodify any of our legacy codes to incorporate the "Use" keyword (exept for the module which deals with compatibility... I can't remember its name offhand). Probably not great reasons, and I would love to hear any argument which would put my concerns more at ease.

0 Kudos
IanH
Honored Contributor III
1,014 Views
You could use sequence association as long as you do all your rank one work in a procedure.

[fortran]! ifort /check:all /warn:all /stand:f03 equiv.f90
PROGRAM equiv
  IMPLICIT NONE  
  REAL :: rank_four(2,3,4,5)
  INTEGER :: i
  !****
  rank_four = RESHAPE([(REAL(i), i=1,SIZE(rank_four))], SHAPE(rank_four))  
  CALL proc(rank_four, PRODUCT(SHAPE(rank_four)))  
  PRINT "(99(4(F8.1,:),/))", rank_four  
CONTAINS
  SUBROUTINE proc(rank_one, N)
    INTEGER, INTENT(IN) :: N
    REAL, INTENT(INOUT) :: rank_one(N)
    !****
    rank_one(N-1) = -1.0       ! Ok.
!    rank_one(N+1) = -2.0      ! Not ok.
  END SUBROUTINE proc
END PROGRAM equiv
[/fortran]


"Recent" (for several years now) versions of gfortran support the C interoperability features of F2003. It tends to be one of the earlier F2003 features implemented by vendors because it is pretty useful.

I can accept that there might be too few F2003 compilers out there to adopt it today, but to be limiting yourself to F77 twenty years after F90 (or even F95) was published, given the language improvements made with that version of the standard, is crazy.
0 Kudos
Steven_L_Intel1
Employee
1,014 Views
Current gfortran should not have any problem with this code. There is no excuse on any reasonable platform today to be using a compiler that does not support this feature of F2003.
0 Kudos
Reply