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

reinterpret cast for arrays

tom_p
Beginner
1,535 Views
I would have thought the following is a common problem, but I did not find a satisfactory solution: Many subroutines defined for real arrays work as well for a complex array if it is interpreted as a real array of double size. For example some of our programs do this:

[fortran]subroutine callee(arr, N)
integer, intent(in) :: N
real, dimension(1:N), intent(in) :: arr

! do stuff
end subroutine callee

subroutine caller()
complex, dimension(1:10) :: arr

! [...]
call callee(arr, 20)
end subroutine caller
[/fortran]

This actually compiles and works if callee is defined in an external subprogram, but of course it violates the standard and breaks if the gen-interfaces compiler switch is used.

Is there any "clean" solution to do this, apart from defining callee twice (once for real and once for complex arguments)? An equivalence statement is not an option as it cannot be used with dummy arguments.

I'd also like to ask the same question with regard to multi-dimensional arrays interpreted as one-dimensional. Here I could of course use the reshape intrinsic, but that implies a lot of copying and therefore cannot generally be used.

(As a side note: the gen-interfaces switch generates interfaces but no compile time error if an external statement exists; is this the intended behavior?)
0 Kudos
1 Solution
Steven_L_Intel1
Employee
1,535 Views
There are various ways to handle this. First, Intel Fortran has an extension called the NO_ARG_CHECK attribute. When this is specified on a routine or a dummy argument, it disables compile-time checks for type, rank and kind. So you could add:

!DEC$ ATTRIBUTES NO_ARG_CHECK :: arr

in "caller" to avoid the generated interface errors.

The Fortran TRANSFER intrinsic is sort of like reinterpret_cast in that it gives you a result with the same bits, just as a different type.

You can also do something like this:

[fortran]subroutine callee(arr, N)
  use iso_c_binding
integer, intent(in) :: N real, dimension(1:N), intent(in) :: arr complex, dimension(:), pointer :: p_arr call c_f_pointer (c_loc(arr), p_arr, [N/2]) ! do stuff with p_arr end subroutine callee[/fortran]

A third option is to use generic interfaces that all bind to the same routine using ALIAS.

I can't reproduce the issue you raise regarding EXTERNAL. Can you show an example?

View solution in original post

0 Kudos
3 Replies
Steven_L_Intel1
Employee
1,536 Views
There are various ways to handle this. First, Intel Fortran has an extension called the NO_ARG_CHECK attribute. When this is specified on a routine or a dummy argument, it disables compile-time checks for type, rank and kind. So you could add:

!DEC$ ATTRIBUTES NO_ARG_CHECK :: arr

in "caller" to avoid the generated interface errors.

The Fortran TRANSFER intrinsic is sort of like reinterpret_cast in that it gives you a result with the same bits, just as a different type.

You can also do something like this:

[fortran]subroutine callee(arr, N)
  use iso_c_binding
integer, intent(in) :: N real, dimension(1:N), intent(in) :: arr complex, dimension(:), pointer :: p_arr call c_f_pointer (c_loc(arr), p_arr, [N/2]) ! do stuff with p_arr end subroutine callee[/fortran]

A third option is to use generic interfaces that all bind to the same routine using ALIAS.

I can't reproduce the issue you raise regarding EXTERNAL. Can you show an example?
0 Kudos
tom_p
Beginner
1,535 Views
Thanks a lot for your answer. I must admit I did not understand your third option; if I understand correctly, ALIAS creates a different name for a subroutine visible from the outside, but I do not see how this could be used to override the argument check.

As to the issue of the compiler failing to emit a warning, no wonder you could not reproduce this because it apparently only occurs if the external subroutine is not called from the main program but only in a subroutine. Minimal example:

[fortran]! calltest.f90
program calltest

  implicit none

  external callee  ! if this is commented out ...

  ! ... or if callee() is called here the compiler notices the
  ! interface mismatch

  call main()

contains

  subroutine main()
    integer, parameter :: N = 10
    complex, dimension(1:N) :: arr = 0

    call callee(arr, 2*N)
  end subroutine main

end program calltest


! callee.f90
subroutine callee(arr, N)
  implicit none
  
  integer, intent(in) :: N
  real, dimension(1:N), intent(in) :: arr

  print *, arr
end subroutine callee
[/fortran]


No error is generated with Intel Fortran 10.1 for Windows and 11.1 for Linux with the command "ifort -warn all -gen-interfaces callee.f90 calltest.f90".

PS: The syntax highlighter of this forum seems to have a problem with Internet Explorer 7. The code looks okay in the edit window, but in the preview the line breaks have vanished.

0 Kudos
Steven_L_Intel1
Employee
1,535 Views
The "external" issue you mention is one that has been reported before and will be fixed.

My suggestion regarding alias was a way to have two (or more) signatures for a single routine. For example:

[fortran]interface mysub
subroutine mysub_real (x)
!dec$ attributes alias:"mysub_generic" :: mysub_real
real, dimension(*) :: x
end subroutine mysub_real

subroutine mysub_complex (x)
!dec$ attributes alias:"mysub_generic" :: mysub_complex
complex, dimension(*) :: x
end subroutine mysub_complex
end interface

subroutine mysub_generic (x)
!dec$ attributes alias:"mysub_generic" :: mysub_generic
real, dimension(*) :: x ! or whatever you want
end subroutine mysub_generic
[/fortran]
0 Kudos
Reply