- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I'm trying to use array pointers as an output from a function. The pointer target is a function variable whose size is not fixed. I've noticed that when using these returned pointers in other parts of the code, the values the pointer refers to are somewhat corrupted.
I've provided in the code below an example of what I'm talking about. The three different test functions differ based on how the return array size is assigned. For the code below, these are
- determined from a passed c_ptr (my actual use for the code requires me to use c_ptr, not a regular Fortran pointer or array)
- determined by a global variable
- explicitly defined in the function itself
module math
implicit none
private
public :: rvfunc_rvarg
abstract interface
function rvfunc_rvarg(x,params) result(res)
use, intrinsic :: iso_c_binding
implicit none
real,intent(in) :: x(:)
type(c_ptr),value :: params
real,pointer :: res(:)
end function rvfunc_rvarg
end interface
end module math
program test_func_pointers
use,intrinsic :: iso_c_binding, only : c_loc,c_ptr,c_f_pointer,c_double,c_null_ptr
implicit none
integer :: nf
type(c_ptr) :: params
real,target :: p
real :: x(6)
x = 5.0
nf = 10
p = real(nf)
params = c_loc(p)
print *,'Test func 1'
call test_sub(test_func1,params,x)
print *,'Test func 2'
call test_sub(test_func2,c_null_ptr,x)
print *,'Test func 3'
call test_sub(test_func3,c_null_ptr,x)
contains
!------------------------------------------------------------------------------
!------------------------------------------------------------------------------
subroutine test_sub(func,params,x)
use math, only : rvfunc_rvarg
implicit none
procedure(rvfunc_rvarg) :: func
type(c_ptr),value :: params
real,intent(in) :: x(:)
real,pointer :: ff(:)
ff => func(x,params)
print *, 'ff = ',ff
end subroutine test_sub
!------------------------------------------------------------------------------
function test_func1(x,params) result(RA)
implicit none
real,intent(in) :: x(:)
type(c_ptr),value :: params
real,pointer :: RA(:)
real,target,allocatable :: RAt(:)
integer :: n
real(c_double),pointer :: p
call c_f_pointer(params,p)
n = int(p)
print *,' n = ',n
allocate(RAt(n))
! allocate(RA(n))
RAt = x(2)
RA => RAt
end function test_func1
!------------------------------------------------------------------------------
function test_func2(x,params) result(RA)
implicit none
real,intent(in) :: x(:)
type(c_ptr),value :: params
real,pointer :: RA(:)
real,target :: RAt(nf)
RAt = x(2)
! allocate(RA(nf))
RA => RAt
end function test_func2
!------------------------------------------------------------------------------
function test_func3(x,params) result(RA)
implicit none
real,intent(in) :: x(:)
type(c_ptr),value :: params
real,pointer :: RA(:)
real,target :: RAt(10)
RAt = x(2)
RA => RAt
end function test_func3
end program test_func_pointers
The result I get from this is the following:
Test func 1
n = 10
ff = 0.000000000000000E+000 5.00000000000000 5.00000000000000
5.00000000000000 5.00000000000000 5.00000000000000
5.00000000000000 5.00000000000000 5.00000000000000
5.00000000000000
Test func 2
ff = 5.00000000000000 6.953242939682073E-310 2.343437349384825E-317
6.953242939696697E-310 3.448878599884572E-317 6.953242939648871E-310
6.953242939654405E-310 6.953242939653614E-310 4.940656458412465E-323
3.952525166729972E-323
Test func 3
ff = 5.00000000000000 5.00000000000000 5.00000000000000
5.00000000000000 5.00000000000000 5.00000000000000
5.00000000000000 5.00000000000000 5.00000000000000
5.00000000000000
As you can see, for the first two cases the values ff points to are wrong, especially in the second case. If I uncomment associate(RA(n)) in test_func1&2, the result doesn't change much -- a few more values in test_func2 are correct, but still ff(1) = 0.0 for the test_func1 case. What is the proper way to dynamically assign the size of RA(:)?
I'm using ifort version 15.0.2.
I would appreciate any help or clarification on this matter.
Grgur
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Actually, that is the method that is supposed to work according to the standard. You just need that switch with ifort to make it conform to the standard in this respect. Contexts where [re]allocation are required on default assignment were nonconforming to the standard before f2003, where [re]allocation on assignment was introduced. There are those of us who would prefer that -assume realloc_lhs were the default for ifort rather than the current situation where -assume norealloc_lhs is, but looking at the docs for ifort 16, that change still hasn't been made. See how the default that breaks standard-conforming code caused problems for you?
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
We need a description of the effect of
use math, only : rvfunc_rvarg
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Ah, sorry, here it is
module math
implicit none
private
public :: rvfunc_rvarg
abstract interface
function rvfunc_rvarg(x,params) result(res)
use, intrinsic :: iso_c_binding
implicit none
real,intent(in) :: x(:)
type(c_ptr),value :: params
real,pointer :: res(:)
end function rvfunc_rvarg
end interface
end module math
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I've just noticed a typo when copying my original code. There should be "allocate(RAt(n))" inserted in test_func1 in my original code posting. I've updated the code to reflect that. (This doesn't change the results, it was a copying error)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
In all cases you are returning pointers to unsaved local variables (all called RAt). As soon as the procedure completes, any pointers associated with those variables become undefined - so called "dangling references". Your code is non-conforming.
If you are going to return a pointer (why?) you need to ensure that the object that the pointer references lasts at least until you have been able to capture the value of the pointer in the scope invoking the function.
The method of defining the size of the local array varies where the data for the local array is stored, hence the differences in behaviour. But all three cases have the dangling reference programming error.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I would prefer to return an allocatable array, but I was under the impression that that is not supported. Maybe it was the case in an old compiler I was using previously.
If I add the following function under the "contains" block
function test_func4(x,params) result(RA)
implicit none
real,intent(in) :: x(:)
type(c_ptr),value :: params
real,allocatable :: RA(:)
allocate(RA(nf))
RA = x(2)
end function test_func4
then the printing the values directly works, but assigning them to an unallocated allocatable array doesn't. I could allocate it based on a dummy run of the function, but this is prohibitive if the function evaluation is expensive.
! This is just a snippet to be inserted in the main program above real,allocatable :: result1(:) ! ! This works print *,'test_func4(x,c_null_ptr) = ',test_func4(x,c_null_ptr) ! ! This doesn't work result1 = test_func4(x,c_null_ptr) print *,'result1 = ',result1 ! ! This works, but prohibitive allocate(result1(size(test_func4(x,c_null_ptr)))) result1 = test_func4(x,c_null_ptr) print *,'result1 (after allocate) = ',result1
In this simple example, I could have done allocate(result1(nf)), but in actual use the calling routine is not aware of the return size of the array. What is the proper way of allocating/assigning the array in that case?
Thanks,
Grgur
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Does the syntax that doesn't work in Quote #6 above still fail if compiled with -assume realloc_lhs ?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
No, that works! (I just have to remove the last example because that would be allocating an allocated array.) Thanks for the tip!
Is that the preferred way of about this problem? Is there a solution that is not compiler-dependent?
P.S. I should probably clarify that in Quote #6 by "doesn't work" I was referring to the fact that it doesn't print anything for result1, not that there's a run-time error
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Actually, that is the method that is supposed to work according to the standard. You just need that switch with ifort to make it conform to the standard in this respect. Contexts where [re]allocation are required on default assignment were nonconforming to the standard before f2003, where [re]allocation on assignment was introduced. There are those of us who would prefer that -assume realloc_lhs were the default for ifort rather than the current situation where -assume norealloc_lhs is, but looking at the docs for ifort 16, that change still hasn't been made. See how the default that breaks standard-conforming code caused problems for you?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Repeat Offender wrote:
Actually, that is the method that is supposed to work according to the standard. You just need that switch with ifort to make it conform to the standard in this respect. Contexts where [re]allocation are required on default assignment were nonconforming to the standard before f2003, where [re]allocation on assignment was introduced. There are those of us who would prefer that -assume realloc_lhs were the default for ifort rather than the current situation where -assume norealloc_lhs is, but looking at the docs for ifort 16, that change still hasn't been made. See how the default that breaks standard-conforming code caused problems for you?
Look into -standard-semantics: https://software.intel.com/en-us/node/579529. You might find it useful in gaining a host of capabilities consistent with the Fortran standard rather than having to pick individual aspects with -assume options.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
R.O.'s point was, I think, that /standard-semantics should be the default. However, the warning note "May result in performance loss" that is attached to that option is probably why it is not a default option.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
mecej4 wrote:
R.O.'s point was, I think, that /standard-semantics should be the default. However, the warning note "May result in performance loss" that is attached to that option is probably why it is not a default option.
And my only point was regarding the specific compiler option recommendation by R.O. of -assume realloc-lhs in connection with his comments about standard Fortran features, that if one is considering a broader array of standard features from 2003 and 2008, the compiler option of -standard-semantics is worth knowing about.
Re: the default, I too had brought it up with Intel quite a while ago, but they have reasons to not do so - see message #9 here:
https://software.intel.com/en-us/forums/intel-fortran-compiler-for-linux-and-mac-os-x/topic/520352
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi everybody,
Thanks so much for very helpful comments! Both tips about -assume realloc_lhs and -standard-semantics were very helpful to me. I'm changing my actual code to work with functions returning allocatable arrays instead of pointers, but I expect it to work without problems.
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page