Pointers in Fortran - fortran

Im unsure how the below 2 in C can be represented in Fortran.
*VariableOne (Could be used possibly by using 'inout intent' in functions?
&VariableOne (No clue about how I could do this though)
Could someone tell me how I might be able to replicate this in Fortran? I looked up Pointers in Fortran but couldnt clearly understand what relates to the above two. I was hoping someone here would show me an equivalent to help me understand.

You seem to be confusing two different concepts. Values in Fortran act as though they're passed by reference so you can modify a variable within a function and have its change reflected outside. The intent statements are there to specify what you're going to do with that dummy variable. intent(in) doesn't allow you to change that variable, intent(out) you use it to pass data out of a function and its value is undefined on entry, and intent(inout) means that it can both provide data to the function (not undefined on entry) and write to it as well.
But there are also explicit pointers you can use to dynamically allocate memory and act similarly to pointers in C.
Pointers in Fortran can't point to just anything. What they point to must have the target attribute or be a pointer. You also don't need to explicitly dereference a pointer to access its value. Here's a short example of what you can do with pointers and how they work:
real, pointer :: ptr(:) => null() !Can point to an array of reals or be allocated
real, target, allocatable :: trgt(:) !Array of reals
real, allocatable :: array(:)
real, pointer :: scalar => null() !Initially points to null to signify that it's not associated
!I can check if the pointer currently points to anything by using the associated function
!Be careful: the initial associaton status is undefined so you must set it to null or nullify it first
if (associated(ptr)) then
nullify(ptr) !Redundant in this example, same as setting it equal to null()
end if
allocate(ptr(3)) !I can allocate a pointer directly with memory for 3 elements
allocate(trgt(5)) !Allocate the target with 5 elements
allocate(array(6)) !Allocate array
!Assign values to my freshly allocated variables
ptr = 1.0
trgt = 3.0
array = 5.0
deallocate(ptr) !Avoid memory leaks by deallocating memory before pointing to something else
ptr => trgt !Pointer now points to the data stored in trgt. No need to use anything like '&' to reference trgt
ptr => array !Error because array does not have target attribute
scalar => ptr(1) !Both are pointers so no error, now points to a value of 3.0
print *, scalar + 5.0 !I can use this value directly without dereferencing it and prints 8.0

Related

Can you test for nullpointers in Fortran?

I'm trying to learn Fortran2018 using gfortran.
When playing around with pointers I noticed that there doesn't seem to be a facility to test for nullpointers. So I have two questions:
Is there really no (straightforward) way to test if a pointer is a nullpointer or "ready to use" in Fortran?
If there isn't, why wasn't it considered necessary in Fortran so far?
More practically speaking, in the code snippet below: How could we find out at any point during execution if assigning to p was "safe" or not? (Possibly imagining a more complex sequence of allocate, nullify, and deallocate statements.)
program test
implicit none
real, pointer :: p
! p = 333.333 ! Segfault, p is neither defined, nor allocated
! Since p is not defined, checking whether it's
! associated to a target gives arbitrary results:
print *, "Start: Pointer p associated? ", associated(p) ! Result: True or False
nullify(p) ! Now p is defined, but `null`
print *, "Nullyfied: Pointer p associated? ", associated(p) ! False
! p = 123.456 ! Still a segfault
allocate(p) ! Now p can be accessed
print *, "Allocated: Pointer p associated? ", associated(p) ! True
p = 987.654 ! Now assignment is possible
allocate(p) ! Loses the value pointed to by p.
print *, p ! Result: 0.00000000
deallocate(p) ! Now accessing p generates a segfault again.
print *, "Deallocated: Pointer p associated? ", associated(p) ! False
! Never allowed:
! allocated(p)
! p == null()
! p .eqv. null()
end program test
In general, there is no safe way to tell whether a pointer is "ready to use", just as there is no safe way to tell whether a variable is currently defined.
The ASSOCIATED intrinsic function may be used only when the pointer is of defined association status, but there is no comparable way to determine (within the Fortran program itself) whether the pointer is of defined association status.
If the pointer is of defined association status, ASSOCIATED will tell you whether or not the pointer points to something (and can even be used in some cases whether it points to a particular thing) and can be used.
However, if the pointer is not of defined pointer association, an attempt to query its association status is a violation of the Fortran standard (this is stronger than the result being undefined, it means your entire program is broken).
You can help yourself by taking reasonable steps to ensure that the pointer association status does not become, or start as, undefined, but it's entirely your responsibility as a programmer to know whether or not the association status is defined.
One way to help is by setting the initial association status of your pointers:
real, pointer :: p => NULL() ! Defined association status, not-associated
real, pointer :: q ! Undefined association status
print *, ASSOCIATED(p) ! Allowed
print *, ASSOCIATED(q) ! Not allowed
end
(I won't say that ASSOCIATED(p) tells us .FALSE., because that ASSOCIATED(q) means we don't have a valid program.)
To conclude, if you're careful you can use ASSOCIATED reliably to tell whether a pointer is associated, but you must be careful.
One tests for null pointers using the associated() function. It returns true for associated pointers and false for null pointers.
For undefined pointers the result is "undefined behaviour" (one can get anything).

Fortran: intent(out) and assumed-size arguments

Suppose an dummy argument is modified in a subroutine, and the subroutine doesn't care about its initial value. For a scalar of the standard numerical types (no components), intent(out) would be correct, right?
Now, if the dummy argument is allocatable and the subroutine depends on its allocation status, or if it has components that are not modified by the subroutine but should maintain their initial values (i.e. not become undefined), or, similarly, if it's an array and not all elements are set in the subroutine... Then the proper intent would be intent(inout).
My question is what happens if the dummy argument is an assumed-size array (dimension(*))? Assuming that not all elements are modified in the subroutine and one wants the other elements to retain their initial values, would intent(out) be appropriate? My reasoning is that the subroutine doesn't "know" the size of the array, so it cannot make the elements undefined as it can with a fixed-size array.
Does the standard say anything about this or are compilers free to "guess" for example that if I set A(23) = 42, then all elements A(1:22) can be made undefined (or NaN, or garbage...)?
Note: When I say "retain their initial values", I mean the values in the actual argument outside the subroutine. The subroutine itself doesn't care about the values of these elements, it never reads them or writes them.
Another question looks at what "becomes undefined" means in terms of the dummy argument. However, exactly the same aspects apply to the actual argument with which the dummy argument is associated: it becomes undefined.
The Fortran standard itself gives a note on this aspect "retaining" untouched values (Fortran 2018, 8.5.10, Note 4):
INTENT (OUT) means that the value of the argument after invoking the procedure is entirely the result of executing that procedure. If an argument might not be redefined and it is desired to have the argument retain its value in that case, INTENT (OUT) cannot be used because it would cause the argument to become undefined
That note goes on further to consider whether intent(inout) would be appropriate for when the procedure doesn't care about values:
however, INTENT (INOUT) can be used, even if there is no explicit reference to the value of the dummy argument.
That the array is assumed-size plays no part in the undefinition of the actual and dummy arguments. Again, to stress from my answer to the other question: "undefined" doesn't mean the values are changed. As the compiler has no required action to perform to undefine values, it doesn't need to work out which values to undefine: with an assumed-size dummy argument the procedure doesn't know how large it is, but this doesn't excuse the compiler from "undefining" it, because there's nothing to excuse.
You may well see that the "undefined" parts of the assumed-size array remain exactly the same, but intent(inout) (or no specified intent) remains the correct choice for a compliant Fortran program. With copy-in/copy-out mechanics with intent(out), for example, the compiler wouldn't be obliged to ensure the copy is defined and that junk isn't copied back.
Finally, yes a compiler (perhaps in the hope of being a good debugging compiler) may change values which have become undefined. If the procedure references the n-th element of an array, it's allowed to assume that there are n-1 elements before it and set them as it chooses, for an intent(out) dummy, but not an intent(inout) dummy. (If you access A(n)then the compiler is allowed to assume that that element, and all from the declared lower bound, exist.)

Reset (deallocate / nullify) a Fortran allocatable array that has been corrupted

When a situation such as described in Incorrect fortran errors: allocatable array is already allocated; DEALLOCATE points to an array that cannot be deallocated happens (corrupted memory leaves an allocatable array that appears allocated but does not "point" to a valid address), is there anything that can be done within Fortran to cure it, i.e., reset the array as deallocated, without trying to deallocate the memory it points to?
The situation is a Fortran/C program where a piece of C code purposefully corrupts (writes garbage to) allocated memory. This works fine for arrays of normal types. But with an allocatable array of a user-defined type, which includes itself an allocatable component, the garbage written to the portion belonging to the allocatable component means that now the component appears as allocated, even though it's not. Rather than making the C code aware of what it should corrupt or not, I'd prefer fixing it after, but "nullifying" the allocatable component, when I know I don't care about the memory it currently appears to point to. With a pointer, it would be just a matter of nullify, but with an allocatable array?
If the memory is really corrupted as in stack corruption/heap corruption. You cannot do anything. The program is bound to fail because the very low-level information is lost. This is true for any programming language, even C.
If, what is corrupted, is the Fortran array descriptor, you cannot correct it from Fortran. Fortran does not expose these implementation details to Fortran programmers. It is only available via special headers called ISO_Fortran_binding.h from C.
If the only corruption that happened was making Fortran thing that the array is allocated where it isn't, it should be rather simple to revert that from C. All it should be necessary is to change the address of the allocated memory. Allocatable arrays are always contiguous.
One could also try dirty tricks like telling a subroutine that what you are passing is a pointer when it in fact is an allocatable and nullify it. It will likely work in many implementations. But nullifying the address in a controllable way is much cleaner. Even if it is just a one nullifying C function you call from Fortran.
Because you really only want to change the address to 0 and not make any other special stuff with the array extents, strides and other details, it should be simple to do even without the header.
Note that the descriptor will still contain nonsense data in other variables, but those should not matter.
This is a quick and dirty test:
Fortran:
dimension A(:,:)
allocatable A
interface
subroutine write_garbage(A) bind(C)
dimension A(:,:)
allocatable A
end subroutine
subroutine c_null_alloc(A) bind(C)
dimension A(:,:)
allocatable A
end subroutine
end interface
call write_garbage(A)
print *, allocated(A)
call c_null_alloc(A)
print *, allocated(A)
end
C:
#include <stdint.h>
void write_garbage(intptr_t* A){
*A = 999;
}
void c_null_alloc(intptr_t* A){
*A = 0;
}
result:
> gfortran c_allocatables.c c_allocatables.f90
> ./a.out
T
F
A proper version should use ISO_Fortran_binding.h if your compiler provides it. And implicit none and other boring stuff...
A very dirty (and illegal) hack that I do not recommend at all:
dimension A(:,:)
allocatable A
interface
subroutine write_garbage(A) bind(C)
dimension A(:,:)
allocatable A
end subroutine
subroutine null_alloc(A) bind(C)
dimension A(:,:)
allocatable A
end subroutine
end interface
call write_garbage(A)
print *, allocated(A)
call null_alloc(A)
print *, allocated(A)
end
subroutine null_alloc(A) bind(C)
dimension A(:,:)
pointer A
A => null()
end subroutine
> gfortran c_allocatables.c c_allocatables.f90
c_allocatables.f90:27:21:
10 | subroutine null_alloc(A) bind(C)
| 2
......
27 | subroutine null_alloc(A) bind(C)
| 1
Warning: ALLOCATABLE mismatch in argument 'a' between (1) and (2)
> ./a.out
T
F

Have a function in fortran return a reference that can be placed on the left-hand-side of an assignment

As stated in the title, I want to directly modify data that I access through a pointer retrieved from a function. Having a reference returned by a function appearing on the l.h.s. of an assignment(=) is no issue in C++ but the following minimal example in fortran errors out:
module test_mod
implicit none
integer, target :: a=1, b=2, c=3 ! some member variables
contains
function get(i)
integer, pointer :: get
integer, intent(in) :: i
select case (i)
case (1)
get => a
case (2)
get => b
case (3)
get => c
end select
end function get
end module test_mod
program test
use test_mod
implicit none
integer, pointer :: i_p
!> prints out 1 2 3
print*, get(1), get(2), get(3)
!> this is what I want but I get the error
!> Error: 'get' at (1) is not a variable
get(2) = 5
!> this works but is not what I want
i_p => get(2)
i_p = 5
end program test
Is there any way to accomplish this behaviour; maybe I'm missing some attributes? I would like to bypass writing any setter routines such as
set(i,value)
since it should mimic the appearance of an array.
In my application, the member variables a,b,c are actually arrays of different size
a = [a1, a2, a3]
b = [b1, b2]
c = [c1]
and I want the getter get(i,j) to mimic a matrix of pointers
j = 1 2 3
i = 1: [[a1, a2, a3],
i = 2: [b1, b2, XX],
i = 3: [c1, XX, XX]]
wehre XX would be referencing to null().
Update:
I am using gfortran (version 5.2.0) and the deployment machines would have only versions starting from 4.6.x and upwards. Therefore, the suggested fortran 2008 standard features are unfortunately not available to me. Is it possible to mimic the behaviour described above without having a compiler supporting it out of the box?
Update 2:
So I ended up implementing a structure as follows
type Vec_t
integer, allocatable, dimension(:) :: vec
end type Vec_t
type(Vec_t), allocatable, dimension(:), target :: data
which I initialise like this (my triangular matrix application I mention at the end)
allocate(data(max))
do i=1,max
allocate(data(i)%vec(i))
end do
and I access & write to it through
print*, data(2)%vec(1)
data(2)%vec(1) = 5
which is not precisely what I was after but good enough for my application.
Let's look at what you want to do:
get(2)=5
and the error message
Error: 'get' at (1) is not a variable
That looks pretty comprehensive: you can't do what you want. Or, perhaps...
get(2) is indeed, under the rules of Fortran 2003, not a variable. In Fortran 2003 a variable is given by the rules R601 and R603, which is a list of designators.
The left-hand side of an assignment must be a variable.
But look at Fortran 2008 and its definition of a variable. Now a variable is either one of those same designators (or ones related to coarrays or complex parts), but it could also (C602 to R602) be a function reference which
shall have a data pointer result.
This is summarized in the introduction of Fortran 2008, detailing the extensions over Fortran 2003, as
A pointer function reference can denote a variable in any variable definition context.
get(2) is a reference to a function that has a data pointer result. get(2) then may appear on the left-hand side of an assignment statement under the rules of Fortran 2008.
Alas, this interpretation of Fortran is not widely supported by current compilers: at the time of answering just the Cray compiler.
This means that this answer is really saying that you have two options: switch compiler or wait until this feature is more widespread. As both of these are likely impractical, you probably want another answer which gives something slightly more portable as a workaround.
I prefer my link to that given by innoSPG, as although this latter is based on the former, the description of the appropriate field "Pointer functions - pointer function ref is a variable" is slightly more clear. This is, though, a more accessible document and a viable alternative.

How can I get a unique value from a fortran pointer

I have a fortran pointer, referring to some allocated memory. I want to "hash" it so that I get a unique number referring to that memory. In C, I would convert the pointer location to an integer.
In Fortran 95 I don't believe this is possible in a strictly standard conforming way. You would need to use vendor extensions - the necessary capability is often available via an intrinsic called LOC or similar.
In Fortran 2003, depending on the nature of the object being pointed to by the Fortran pointer, you could convert the C address of the object (its memory location) to an integer.
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_LOC, C_INTPTR_T
TYPE(thing), POINTER :: object
INTEGER(C_INTPTR_T) :: an_integer
!****
ALLOCATE(object)
an_integer = TRANSFER(C_LOC(object), an_integer)