常见块

在 Fortran 的早期形式中,从子例程和函数可见的唯一创建全局变量存储的机制是使用 COMMON 块机制。这允许变量序列成为名称并共享共享。

除了命名的公共块之外,还可能存在空白(未命名)公共块。

可以声明一个空白的公共块

common i, j

而命名块 variables 可以声明为

common /variables/ i, j

作为一个完整的例子,我们可以想象一个可以添加和删除值的例程使用的堆存储:

       PROGRAM STACKING
       COMMON /HEAP/ ICOUNT, ISTACK(1023)
       ICOUNT = 0
       READ *, IVAL
       CALL PUSH(IVAL)
       CALL POP(IVAL)
       END

       SUBROUTINE PUSH(IVAL)
       COMMON /HEAP/ ICOUNT, ISTACK(1023)
       ICOUNT = ICOUNT + 1
       ISTACK(ICOUNT) = IVAL
       RETURN
       END

       SUBROUTINE POP(IVAL)
       COMMON /HEAP/ ICOUNT, ISTACK(1023)
       IVAL = ISTACK(ICOUNT)
       ICOUNT = ICOUNT - 1
       RETURN
       END

通用语句可用于隐式声明变量的类型并指定 dimension 属性。仅此行为通常是混淆的充分来源。此外,隐含的存储关联和跨程序单元的重复定义的要求使得使用公共块容易出错。

最后,公共块在它们包含的对象中非常受限制。例如,公共块中的数组必须具有显式大小; 可分配的对象可能不会发生; 派生类型不得具有默认初始化。

在现代 Fortran 中,这些变量的共享可以通过使用模块来处理。上面的例子可以写成:

module heap
  implicit none
  ! In Fortran 2008 all module variables are implicitly saved
  integer, save::count = 0
  integer, save::stack(1023)
end module heap

program stacking
  implicit none
  integer val
  read *, val
  call push(val)
  call pop(val)

contains
  subroutine push(val)
    use heap, only : count, stack
    integer val
    count = count + 1
    stack(count) = val
  end subroutine push

  subroutine pop(val)
    use heap, only : count, stack
    integer val
    val = stack(count)
    count = count - 1
  end subroutine pop
end program stacking

命名空白公共块的行为略有不同。值得注意的是

  • 最初可以定义命名公共块中的对象; 空白常见的物体不得
  • 空白公共块中的对象表现得好像公共块具有 save 属性; 当块不在活动程序单元的范围内时,没有 save 属性的命名公共块中的对象可能变为未定义

后一点可以与现代代码中模块变量的行为形成对比。Fortran 2008 中的所有模块变量都是隐式保存的,当模块超出范围时不会变为未定义。在 Fortran 2008 模块变量(如命名公共块中的变量)之前,当模块超出范围时,它们也将变为未定义。