What is the point of BLOCK in Fortran?

前端 未结 3 1689
别那么骄傲
别那么骄傲 2020-12-19 05:40

I am looking at some code and there is this:

BLOCK

...lines of code...

END BLOCK

What is the purpose of BLOCK? I tried to go

相关标签:
3条回答
  • 2020-12-19 05:52

    I have composed a few more fun examples. What if you want to invoke an assumed length function with different lengths in the same instance of a subprogram? You need a specification statement to tell the compiler the length you want, so a BLOCK construct can do this for you

    function F(x)
       implicit none
       character(*) F
       character x(:)
       integer i
       do i = 1, len(F)
          F(i:i) = x(1)
       end do
    end function F
    
    program blox1
       implicit none
       integer i
       character c
       do i = 1, 7
          c = achar(65+modulo(i**4+6*i**2+1,26))
          block
             character(2*i+1), external :: F
             call blox1a(F)
          end block
       end do
       contains
          subroutine blox1a(F)
             interface
                function F(x)
                   import
                   implicit none
                   character(2*i+1) F
                   character x(:)
                end function F
             end interface
             write(*,'(a)') F([c])
          end subroutine blox1a
    end program blox1
    

    Output with gfortran:

    III
    PPPPP
    GGGGGGG
    PPPPPPPPP
    WWWWWWWWWWW
    FFFFFFFFFFFFF
    SSSSSSSSSSSSSSS
    

    Or how about when you need the appropriate KIND for a REAL literal? This requires a named constant and the KIND might be given in the specification statements of another MODULE and may even be given as an expression. In that case you might try defining a named constant with the value of that expression, but if an unlucky choice is made that name might override another host associated name. A BLOCK construct makes it all OK:

    module mytypes
       use ISO_FORTRAN_ENV
       implicit none
       type T(KIND)
          integer, kind :: KIND
          real(KIND) x
       end type T
       interface assignment(=)
          module procedure assign8, assign4
       end interface assignment(=)
       contains
          subroutine assign8(x,y)
             real(REAL64), intent(in) :: y
             type(T(kind(y))), intent(out) :: x
             x%x = y
          end subroutine assign8
          subroutine assign4(x,y)
             real(REAL32), intent(in) :: y
             type(T(kind(y))), intent(out) :: x
             x%x = y
          end subroutine assign4
    end module mytypes
    
    program blox2
       use mytypes
       implicit none
       type(T(REAL32)) x
    BLOCK
    !   integer, parameter :: rk = x%KIND ! Not allowed
       integer, parameter :: rk = kind(x%x)
       x = 0.0072973525664_rk
       write(*,'(g0)') x%x
    END BLOCK    -1 is too small
    12! = 479001600
    13 is too big
    BLOCK
       type(T(REAL64)) x
    BLOCK
    !   integer, parameter :: rk = x%KIND ! Not allowed
       integer, parameter :: rk = kind(x%x)
       x = 0.0072973525664_rk
       write(*,'(g0)') x%x
    END BLOCK
    END BLOCK
    end program blox2
    

    Output with gfortran:

    0.729735242E-02
    0.72973525663999998E-002
    

    It can be tricky to get a Fortran pointer to a C string because there is no syntax to tell C_F_POINTER what the length of the target of a deferred length pointer should be. BLOCK to the rescue!

    program blox3
       use ISO_C_BINDING
       implicit none
       character(len=:,kind=C_CHAR), allocatable, target :: x
       type(C_PTR) c_hello
       integer(C_INTPTR_T) address
       character(kind=C_CHAR), pointer :: nul_address
       character(len=:,kind=C_CHAR), pointer :: f_hello
       integer i
    
       x = 'Hello, world'//achar(0)
       c_hello = C_LOC(x(1:1))
       address = transfer(c_hello,address)
       i = 0
       do
          call C_F_POINTER(transfer(address+i,C_NULL_PTR),nul_address)
          if(nul_address == C_NULL_CHAR) exit
          i = i+1
       end do
    BLOCK
       character(len=i,kind=C_CHAR), pointer :: temp
       call C_F_POINTER(c_hello,temp)
       f_hello => temp
    END BLOCK
    write(*,'(i0,1x,a)') len(f_hello), f_hello
    end program blox3
    

    Output with gfortran:

    12 Hello, world
    

    Not to mention that a named BLOCK construct gives us a label to hang our spaghetti code on:

    program blox4
       implicit none
       integer i
       integer j(3)
       integer k
    
       j = [-1,12,13]
    do i = 1, size(j)
    factorial: BLOCK
       if(j(i) < 0) then
          write(*,'(*(g0))') j(i),' is too small'
          EXIT factorial
       end if
       if(j(i) > 12) then
          write(*,'(*(g0))') j(i),' is too big'
          EXIT factorial
       end if
       write(*,'(*(g0))') j(i),'! = ',product([(k,k=1,j(i))])
    END BLOCK factorial
    end do
    end program blox4
    

    Output with gfortran:

    -1 is too small
    12! = 479001600
    13 is too big
    
    0 讨论(0)
  • 2020-12-19 05:58

    The block construct allows you to declare entities such as variables, types, external procedures, etc which are locally known to the block but have no effect to any variables outside of the block.

    Example 1:

    IF (swapxy) THEN
      BLOCK
        REAL (KIND (x)) tmp
        tmp = x
        x = y
        y = tmp
      END BLOCK
    END IF
    

    Here the variable tmp is locally defined to help out with the swap of two variables. Outside of the block, the variable tmp is unknown or back its original form if it was defined outside of the block (see next example).

    Example 2:

    F = 254E-2
    BLOCK
      REAL F
      F = 39.37
    END BLOCK
    ! F is still equal to 254E-2.
    

    The variable F is redefined locally to the block but has no effect outside of it.

    These kinds of blocks are used to make the code more readable and easier to understand as you don't need to look to the entire subprogram to understand what the locally defined entities are. Furthermore, the compiler knows that these entities are locally defined, so it might do some more optimization.

    0 讨论(0)
  • 2020-12-19 06:15

    From the Fortran 2008 standard:

    The BLOCK construct is an executable construct that may contain declarations.

    It is not related to common blocks or to block data program units.

    So, the main use is this "containing declarations".

    As scoping units we have things like

    integer i
    block
      integer j ! A local integer
      integer i ! Another i
      save i    ! ... which can even be SAVEd
    end block
    

    which affords locality of declarations:

    ! ... lots of code
    block
      integer something
      read *, something
    end block
    ! ... lots more code
    

    These scoping blocks allow automatic objects:

    integer i
    i = 5
    block
      real x(i)
    end block
    

    As executable constructs, they also have useful flow control:

    this_block: block
      if (something) exit this_block
      ! ... lots of code
    end block
    

    They also have finalization control:

    type(t) x
    block
      type(t) y
    end block ! y is finalized
    end  ! x is not finalized
    

    for x and y of finalizable type.

    Oh, and let's not forget how you can confuse people with implicit typing.

    0 讨论(0)
提交回复
热议问题