What is the point of BLOCK in Fortran?

前端 未结 3 1698
别那么骄傲
别那么骄傲 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
    

提交回复
热议问题