Can you test for nullpointers in Fortran?
Asked Answered
S

2

6

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:

  1. Is there really no (straightforward) way to test if a pointer is a nullpointer or "ready to use" in Fortran?
  2. 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
Shillong answered 6/5, 2022 at 10:44 Comment(2)
IMO the real point is that you wouldn't use a pointer, that's not the Fortran way. Use an allocatable, with which you can do all you are asking - Second rule of Modern Fortran: "Don't use pointers unless you really have to"Anthrax
And to make explicit @IanBush's comment, unlike pointers, with allocatables it's always (since the broken Fortran 90 was superseded) possible to tell whether an allocatable object is safe to use.Astri
A
7

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.

Astri answered 6/5, 2022 at 11:25 Comment(4)
Thank you for the great answer. I didn't know that using associated() on an undefined pointer violates the standard. If indeed this is the case, I don't understand why the compiler "lets me get away with it". I get a warning form gfortran only if I use -Wall. I tried to compile your example with ifort and couldn't get any warning at all from it.Shillong
You "get away with it" because the compiler is generally under no obligation to see whether you have violated the standard. In this case, it's allowed to assume that you've given a standard-conforming program, rather than being required to test the pointer association definition status and diagnose for you.Astri
How unfortunate :) Anyway, thanks again for the explanation. So I assume that if you put allocate(q) before the print statements in your code example it still wouldn't make the program actually "valid"? Because I noticed, that after calling allocate() on q, I could print its value (0) no problem, even if q wasn't "nullyfied" before that.Shillong
An allocate(q) would suffice: the allocation makes the association status defined (and indeed makes the pointer associated). But with pointers there are two bits of "defined" to consider: association status, and definition. After the allocate(q), it's pointer associated, but you still haven't defined its value: allocate(q); if (associated(q)) print*, q) is invalid, but because of the printing, not querying the association status.Astri
F
5

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).

Falchion answered 6/5, 2022 at 10:47 Comment(1)
Thanks for this very concise answer. It seems I mixed up null pointers with undefined pointers and you made it clear that they're actually not the same.Shillong

© 2022 - 2024 — McMap. All rights reserved.