资源描述
第7章 属性的声明
最后,对于数据我们剩下的工作,就是如何运用FROTRAN语言来完整地加以描述。
FORTRAN语言完成对数据的描述的语法单位是数据声明语句,在前面2章里面,我们整理好问题当中需要涉及的数据及其结构之后,要以FORTRAN语言写下来,就是使用FORTRAN的声明语句,这些语句的句法设计保证能够完备的描述我们关于数据所需要说明的一切属性。
数据对象首先需要予以说明的当然就是它的类型,因此我们首先给出对象的类型声明语句,特别地,需要说明在最初FORTRAN标准里面遗留下来的一种数据类型描述方法——隐式类型描述法,然后讨论各种数据对象所可能具有的属性。
● 数组属性;
● 指针属性;
● 值特征;
● 对象可访问性与使用属性;
● 特征兼容性;
● 自动数据对象;
● 存储关联。
由于本章集中讨论FORTRAN的声明语句,而声明的对象除了数据之外,其他的程序对象,例如函数,过程等也需要声明其类型或属性,因此本章一并讨论对其他程序对象的声明:
● 过程属性;
● NAMELIST语句;
7.1 属性及其声明方式
所谓一个对象的属性,就是程序使用该对象的方式。
本章所讨论的属性的大体分类与作为其名称的关键词见表7-1:
表7-1属性的分类及其关键词
数据类型 INTEGER
REAL(以及DOUBLE PRECISION)
COMPLEX
LOGICAL
CHARACTER
TYPE(派生类型的名称由用户命名)
数组属性 DIMENSION
ALLOCATABLE
指针属性 POINTER
TARGET
值设置 DATA
PARAMETER
对象可访问性与调用 PUBLIC
PRIVATE
INTENT
OPTIONAL
SAVE
过程属性 EXTERNAL
INTRINSIC
对象关系属性 NAMELIST
EQUIVALENCE
COMMON
这些关键词的使用,或者说属性的声明有2种方式:
● 在类型声明时附加属性说明,这种语句形式侧重在给出数据对象,属性说明是附加的;
● 使用单独的属性声明语句,这种语句形式侧重在说明属性本身。
之所以会出现2种声明方式,完全是历史的缘故。FORTRAN的早期版本里,任何的对象属性说明,都是运用单独的属性声明语句,如果一个数据对象同时具有多种属性,就需要使用相应的多个属性声明语句,从程序阅读的角度来看,会显得很烦琐,因此到了FORTRAN90和95版本,只要在程序单元当中需要声明一个数据对象的类型,那么就可以把它的其他所有属性都附加到它的类型声明语句当中,使得程序显得更加紧凑。
【例7-1】 我们要定义2个实型变量X,Y,同时还要声明它们都具有指针属性,在早期FORTRAN语言里写为:
REAL X,Y
POINTER X,Y
换一种更加紧凑的写法就是把这2条语句写为1句:
REAL POINTER::X,Y
之所以我们还需要讨论单独的属性语句,主要是有时候需要保持源码的向前兼容性,而且在少数情况下,这2种形式也并完全等价。因此在本章在讨论各种属性的声明方式的时候,将首先给出面向数据对象的声明方式,然后给出等价的面向属性的声明方式。
在这2种表示属性的方式里,同样由于历史的缘故,数组的维度属性DIMENSION既可以附加在类型声明语句当中表述,也可以单独声明,实际上DIMENSION这个关键词属于老式FORTRAN的遗留物,在新的表述方式里面,完全可以省略它。
【例7-2】
COMPLEX X
DIMENSION X(35)
SAVE X
COMPLEX X(35)
SAVE X
COMPLEX,DIMENSION(35),SAVE::X
COMPLEX,SAVE::X(35)
以上4种表述方式是完全等价的,显然最后一种最简洁。
在一个程序单元里面,引用一个数据对象的前提是已经声明了它的种种必需属性,数据对象的各种属性里面,最为基本的当然是数据对象的类型,然后还需要声明其各种必需的属性,这样该数据对象才能被程序正确地调用访问。然而在一个实际的程序里面,数据对象的声明在表面上可能并不是完备的,同时又不是非法的语法,出现这种情况的原因如下:
● 在FORTRAN的早期版本里,为了求简化的缘故,使用了一种隐式约定数据类型的方式,即通过数据对象的名称的第一个字母来分辨其所属类型,这种类型声明方式被后来的FORTRAN版本一直沿用下来了,因此如果一个程序单元里出现的数据对象没有经过类型声明语句的专门声明,则需要考虑其是否属于隐式声明。相反,如果想排除这种隐式声明的影响,则需要另外单独加以IMPLICIT NONE语句作为声明。
● 任何其他的属性如果没有出现的话,或者是因为该数据对象不需要某种属性,或者是该数据对象的某种属性采取了默认设置。
从上面的分类表7-1可以看到,FORTRAN的属性除了用来说明数据类型的属性之外,其他属性都是针对不同的数据类型或程序对象,以及它们的各种特征的。例如数组属性只是用来说明数组,指针属性只是用来说明指针,而过程属性只是用来说明过程,下面将分类讨论这些属性。
7.2 类型声明语句
我们在讨论第5章讨论数据类型的时候给出数据类型的基本声明语句的句法形式,这里将侧重于数据类型的声明与其他相关属性的兼容,因为从语言的简洁与自然的角度出发,把一个数据对象的类型和其他属性都归结为一条数据声明语句是非常可取的,所以我们得到如下的一般的类型声明句法形式(R501):
type-specification [[ ,attribute- specification]…:: ] entity-declaration-list
即作为选项,在一条数据对象的类型声明(type-specification)语句当中,在数据项声明的列表(entity-declaration-list)之前,给出相应的属性说明(attribute- specification),方括号[]表示可选。
● 类型说明(type-specification)的一般句法形式(R502)是如下几种形式之一:
INTEGER [kind-selector]
REAL [kind-selector]
DOUBLE PRECISION
COMPLEX [kind-selector]
CHARACTER [character-selector]
LOGICAL [kind-selector]
TYPE(type-name)
其中种别选择符(kind-selector)的句法形式(R506)为:
([KIND = ] kind-value)
其中种别值(kind-value)是一个标量整型表达式。
● 属性说明(attribute- specification)的一般句法形式(R503)为如下几种形式之一:
PARAMETER
ALLOCATABLE
DIMENSION(array- specification)
EXTERNAL
INTENT(intent-specification)
INTRINSIC
OPTIONAL
POINTER
SAVE
TARGET
access- specification
其中的可访问性说明(access- specification)包括PUBLIC和PRIVATE。
● 数据项声明的一般句法形式(R505)为如下2种形式之一:
object-name [(array- specification)] [*character-length] [initialization]
function-name [(array- specification)] [*character-length]
其中初始化(initialization)的一般句法形式(R505)为如下2种形式之一:
= initialization-expression
=>NULL()
类型声明的一般规则如下:
● 对数据对象的说明优先于隐式类型描述,即隐式类型描述法永远只是在数据对象没有获得任何说明的情况下的默认法则,而显式说明既可以与隐式法则一致,也可以不一致。
● 在一个类型声明语句当中,同一个属性只能出现一次。
● 在一个作用域内,一个数据项的任何属性只要约定了一次,就不可再次约定。
● 种别选择符所取的种别值只能是编译系统所许可的相应类型的种别参数之一。
● 字符长度(character-length)选项只能出现在CHARACTER类型的声明语句当中。
● 如果使用初始化语句,则必须在数据项声明前使用双冒号(;;)。
● 如果数据变量被初始化设置为数组,那么该数组的形状一定要得到说明,或者是在类型声明语句当中,或者是在同一个作用域内此前的属性声明语句当中。
● 如果数据对象被赋予PARAMETER属性,那么其中必须包含初始化语句。
● 如果在初始化语句当中出现符号=>,那么该被初始化的对象必定具有POINTER属性;如果在初始化语句当中出现符号=,那么该被初始化的对象肯定不具有POINTER属性。
● 所谓函数名称(function-name),或者是一个外部函数的名称,或者是一个固有函数的名称,或者是一个函数哑过程的名称,或者是一个语句函数的名称。
● 一个数组函数名称或者是被指定为显形数组,或者是具有POINTER属性,从而被指定为待定形数组。
有关属性声明的其他规则以及属性之间的兼容性在后面会详悉讨论。
【例7-3】 下面是一些附加了其他属性的数据类型声明语句:
REAL, INTENT(IN) :: COS
REAL, INTRINSIC :: SIN
INTEGER X(25)
LOGICAL,DIMENSION(10,15)::RESULT1,RESULT2
INTEGER,PARAMETER::SHORT=SELECTED_INT_KIND(4)
COMPLEX :: SQUARE_ROOT = ( 2.76, -0.85)
REAL, ALLOCATABLE :: X( : , : )
TYPE, POINTER :: CURRENT_OF_SAMPLE => NULL()
7.2.1 整型
INTEGER语句声明了整型数据对象的名称,同时也可以附加种别参数以及其他属性。如果给出种别选择符,即说明该整型数据的表示方法。
声明一个数据对象属于整型数据的基本语句句法为:
INTEGER [ ( [ KIND = ] kind-value ) ] [ [ , attribute-list] :: ] entry-list
【例7-4】 以下这些声明语句主要是要说明数据项:
INTEGER X
INTEGER DIMENSION(:), POINTER :: days, hours
INTEGER(SHORT)RED_BALL
INTEGER(2) POINTER :: k, limit
INTEGER(1) DIMENSION(10) :: min
【例7-5】 以下这些声明语句主要是要说明数据的属性:
INTEGER days, hours
INTEGER(2) k, limit
INTEGER(1) min
DIMENSION days(:), hours(:), min (10)
POINTER days, hours, k, limit
7.2.2 实型
REAL语句声明了实型数据对象的名称,同时也可以附加种别参数以及其他属性。如果给出种别选择符,即说明该实型数据的表示方法。
双精度实型数据还可以使用DOUBLE PRECISION语句加以声明,当然与在REAL语句当中使用种别参数是完全等价的。由于DOUBLE PRECISION本身指出了精度表示方法,因此不能再在后面附加种别选择符。
不过DOUBLE这个词也可以作为一个命名整型常量,取双精度实型的种别参数值,这样就可以使用REAL(DOUBLE)来声明双精度实型数据了。
实型数据的声明的格式如下:
REAL [ ( [KIND=] kind-value ) ] [ [ , attribute-list] :: ] entry-list
DOUBLE PRECISION [ ,attribute-list] :: ] entry-list
【例7-6】 下面是各种形式的主要说明数据项的声明语句:
REAL (KIND = high), OPTIONAL :: testval
REAL, SAVE :: a(10), b(20,30)
DOUBLE PRECISION,POINTER::A,B(:,:)
DOUBLE PRECISION,DIMENSION(5,10)::TABLE1,TABLE2
REAL(DOUBLE),POINTER::A,B(:,:)
REAL(DOUBLE),DIMENSION(5,10)::TABLE1,TABLE2
【例7-7】 下面是各种形式的主要说明数据属性的声明语句:
REAL (KIND = high) testval
REAL a(10), b(20,30)
OPTIONAL testval
SAVE a, b
DOUBLE PRECISION TABLE1,TABLE2
DIMENSION TABLE1(5,10),TABLE2(5,10),B(:,:)
POINTER A
可以比较什么两种表示方法,在说明了同样的意思的前提下,把属性说明附加在数据类型说明语句当中,比每一种属性单独一个语句加以说明要简洁自然得多。
7.2.3 复型
COMPLEX语句声明了复型数据对象的名称,同时也可以附加种别参数以及其他属性。如果给出种别选择符,即说明该复型数据的表示方法。说明复型数据类型的句法为:
COMPLEX [([KIND = ] kind-value ) ] [ [ , attribute-list] :: ] entry-list
【例7-8】 下面是各种形式的复型数据对象声明语句:
COMPLEX ch
COMPLEX (KIND=4),PRIVATE :: zz, yy !等价于COMPLEX*8 zz, yy
COMPLEX(8) ax, by ! 等价于COMPLEX*16 ax, by
COMPLEX (kind(4)) y(10)
complex (kind=8) x, z(10)
7.2.4 逻辑型
LOGICA语句声明了逻辑型数据对象的名称,同时也可以附加种别参数以及其他属性。如果给出种别选择符,即说明该逻辑型数据的表示方法。说明逻辑型数据类型的句法为:
LOGICAL [([KIND = ] kind-value ) ] [ [ , attribute-list] :: ] entry-list
【例7-9】 下面是各种形式的主要说明逻辑型对象的声明语句:
LOGICAL, ALLOCATABLE :: flag1, flag2
LOGICAL (KIND = byte), SAVE :: doit, dont
【例7-10】 下面是各种形式的主要说明对象的属性的声明语句:
LOGICAL flag1, flag2
LOGICAL (KIND = byte) doit, dont
ALLOCATABLE flag1, flag2
SAVE doit, don’t
7.2.5 字符型
CHARACTER语句声明了字符型数据对象的名称,同时也可以附加种别参数以及其他属性。如果给出字符选择符,即说明该字符型数据的最大字符长度。说明字符型数据类型的句法为:
CHARACTER [character-selector] [ , attribute-list :: ] entry-list
其中的字符选择符(character-selector)的句法形式(R507)可以为如下几种:
length-selector
(LEN =length-value , KIND = kind-value )
(length-value , [ KIND = ] kind-value )
(KIND = kind-value [,LEN =length-value] )
其中长度选择符(length-selector)的句法形式(R508)可以是:
([LEN =] length-value)
* character-length[ ,]
其中字符长度(LEN)(R509)可以是:
(length-value)
scalar-integer-literal-constant
其中长度值(length-value)(R510)可以是:
specification-expression
*
在上面的类型说明当中,使用星号*来标志字符长度的方式属于过时的方式,不过不是指在数据项里面使用的星号*。
字符型数据对象类型声明语句的一般规则如下:
● 只有在没有使用双冒号的情况下,在长度选择符里才可以使用逗号。
● 字符型数据对象的字符长度在一定的情形下,是可以发生动态变化的,即当一个字符型数据的声明语句出现在一个过程或者是过程界面当中,同时该数据对象又不是某个派生数据对象的成员,那么它的字符长度可以使用非常量表达式,该表达式的具体取值只有当访问该过程时才被确定,并且当该过程的运行时,表达式里变量的变化并不影响字符长度值。这样一种数据对象如果不属于哑元,则属于自动数据对象的范畴。
● 字符长度的说明有三种情形:
• 首先在数据项或数据项列的成员里给出字符长度;
• 如果没有上面的长度说明,则在数据类型说明部分给出命名字符数据项或派生类型定义当中的字符成员的字符选择符,用来给出长度属性;
• 如果一个字符型数据既没有使用字符选择符,也没有使用字符长度来说明其长度,那么默认的字符长度为1。
● 如果长度参数取负值,那么相应的字符项长度为0。
● 给定了字符长度的标量整型文字常量不能再附加任何种别参数,否则在固定源码形式里面就会导致歧义。
● 采用带星号*的长度说明只能使用于以下几种情形:
•可以应用于过程的哑元,当过程被调用时,哑元就被赋予相应实元的长度;
•可以用于声明命名常量,这时它的长度是一个常量值;
•可以用于声明一个外部函数的结果变量的长度。任何调用该函数的作用域单元如果使用带星号的长度说明,就意味着主程序可以访问该声明。当函数被调用的时候,结果变量的长度的取值由引用该函数的程序单元里面的相应声明语句决定。
本规则暗示了在IMPLICIT语句当中不能使用带星号*的长度说明方式。
● 如果一个函数属于内部函数或模块函数,或者该函数的值为数组,指针或递归形式,那么该函数名不能使用带星号*的长度声明。
● 字符值语句函数或字符型语句函数哑元的长度必须是整型常量表达式。
【例7-11】 下面是各种形式的主要说明字符型数据对象的声明语句:
CHARACTER (LEN=25,KIND=GREEK),DIMENSION(11)::Z1
CHARACTER (LEN=20,KIND=KANJI),SAVE::GREETING(2)
CHARACTER (10)::QUESTION=“WHERE?”
CHARACTER (LEN=*,KIND=CHINESE),PARAMETER::MESSAGE = &
“简朴是语言的一种美德”
CHARACTER (*),INTENT(IN)::SCHOOL, HOME
CHARACTER *3, SAVE :: COMPONENT_1, LONGER(9) *20, COMPONENT_2
CHARACTER :: RESULT = “PASS”
例7-12:下面是各种形式的主要说明字符型数据的属性的声明语句:
CHARACTER (70)PROJECT
CHARACTER (LEN=30, KIND=GERMAN)TRANSFORMATION
CHARACTER (LEN=25,KIND=GREEK)Z1
CHARACTER (LEN=20,KIND=KANJI)GREETING(2)
CHARACTER (10)QUESTION
CHARACTER (*)SCHOOL, HOME
CHARACTER *3 COMPONENT_1, LONGER(9) *20, COMPONENT_2
CHARACTER RESULT
SAVE GREETING(2)
INTENT(IN)SCHOOL, HOME
DATA QUESTION /“WHERE?”/
CHARACTER (*)MESSAGE
PARAMETER( MESSAGE = &
“简朴是语言的一种美德”)
7.2.6 派生类型
TYPE语句声明了用户派生数据类型对象的名称,派生类型的名称写在紧跟TYPE后面的一对括号当中,声明派生类型的数据对象的一般句法为:
TYPE(type-name)[ , attribute-list :: ] entry-list
派生类型声明语句的一般规则如下:
● 如果一个派生类型对象是私有的话,就不能附加PUBLIC属性。
● 结构构造器必须用来初始化派生类型数据对象,结构构造器里的表达式必须是初始化表达式。
● 如果需要声明的派生数据对象是一个函数的结果,那么它就可以在FUNCTION语句当中予以说明。
【例7-13】 下面是各种形式的主要说明派生数据对象的声明语句:
TYPE(SAMPLE),DIMENSION( :),ALLOCATABLE::STOVE
TYPE(STUDENT),SAVE::GRAD(5)
TYPE(HOMEWORK),SAVE::QUESTION,TAPE,WORD_SHEET
【例7-14】 下面是各种形式的主要说明派生数据对象的属性的声明语句:
TYPE(SAMPLE)STOVE
TYPE(STUDENT)GRAD(5)
TYPE(HOMEWORK)QUESTION,TAPE,WORD_SHEET
DIMENSION STOVE( :)
ALLOCATABLE STOVE
SAVE GRAD(5), QUESTION,TAPE,WORD_SHEET
注意上面这两种说明方法里面标点的不同用法。
7.3 隐式类型描述法
当初FORTRAN使用隐式类型声明方法,是与语言的简朴形态相适应的,在硬件资源相对紧缺的时代,简朴也能成为语言的一种美德,不过如果到了硬件资源相对富余的今天,还吝啬于增加几个关键词和几条声明语句,就会显得很落伍了,所以后来就增加了更为接近自然语言的声明语句,不过,为了缅怀FORTRAN语言作为祖母级高级语言的荣耀,隐式类型声明方式还是保留下来了,甚至默认为总是起作用,除非首先声明了IMPLICIT NONE语句。
当然,只要你乐意使用,这种类型声明方式在某些情况下,还是非常方便简明的。
隐式类型声明方法的出发点,是考虑到任何需要加以类型声明的对象,如变量,命名常量,函数等,都需要一个名称来指称,那么就可以把它的类型这个信息负载在它的名称上,最简单的约定,就是让名称的第一个字母来标记它的类型,例如在默认的情形下:
REAL: A B C D E F G H
INTEGER: I J K L M N
REAL: O P Q R S T U V W X Y Z
可以发现,上面对字母的默认分配并不是很难记忆,FORTRAN沿用了数学里的很多习惯,这里使用I,J,K,L,M,N来表述整数,就是一个明显的数学习惯。
除了上面默认的首字母隐式类型法则,隐式类型声明方法还有很灵活的一面,即利用IMPLICIT语句来自定义字母分配模式,一般的IMPLICIT语句的句法形式(R541)有2种,分别行使不同的功能:
IMPLICIT type-specification(letter-specification-list)
IMPLICIT NONE
其中的字母分配说明列表的句法形式(R543)为:
letter[-letter]
这里IMPLICIT后面的字母分配表定义可以完全是自由定义,并且只是在该语句的作用域内有效,而任何名称在它的作用域内只要是没有专门的类型声明语句,也没有IMPLICIT语句,那么它就遵循上面的默认首字母隐式类型法则。
隐式类型的一般规则如下:
● 如果要使用IMPLICIT NONE语句,那么它必须放置在任何PARAMETER语句之前,并且在其作用域内,再也不能出现其他IMPLICIT语句。
● IMPLICIT语句当中出现的表述字母范围的letter-letter,左边的字母绝对不能是右边字母的按照字母表顺序的后面的字母。
● letter-letter的字母之间为减号,而非下划线,表示按照字母表顺序从左边字母到右边字母的所有字母。
● 在一个作用域里面的IMPLICIT语句里面,同一个字母不能出现在字母分配说明列表里面的不同项里,例如作为单个字母出现了,又同时处于另一个字母范围之中,或同时处于2个不同的字母范围里面。
● IMPLICIT语句同样可以用来为派生数据类型分配首字母作为类型标记。
默认的首字母隐式类型法则与IMPLICIT语句之间的关系值得特别加以注意。
例如给出约定:
IMPLICIT COMPLEX(E-G,W-Z)
然后在该语句的作用域里再也没有其他IMPLICIT语句,也没有类型声明语句,那么在该作用域内具有不属于(E-G,W-Z)这个范围的首字母的变量,将遵循默认首字母分配表,即首字母在范围(A-D,H,O-V)内的变量属于实型,而首字母在范围(I-N)内的变量属于整型。
IMPLICIT NONE可以用来检查名称的错误拼写,因为如果不加以这个语句的话,即使错误拼写的名称,也会被看成遵循首字母隐式类型声明方法的具有确定数据类型的变量,从而能够通过语法检查,反之使用该语句,就可以避免这种误解。
【例7-15】 下面的IMPLICIT语句都是合法语句:
IMPLICIT CHARACTER*30(B,T),COMPLEX(W-Z)
IMPLICIT LOGICAL(KIND=BIT)(Q)
IMPLICIT REAL(QUAD)(X-Z)
IMPLICIT TYPE(NUMBER)(A-E)
IMPLICIT TYPE(ARTICAL)(A,V),CHARACTER*100(B)
【例7-16】 下面的IMPLICIT语句都是非法语句:
IMPLICIT CHARACTER*30(B,T),COMPLEX(Z -W)!W应该放置在Z 之!前。
IMPLICIT LOGICAL(KIND=BIT)(Q),REAL(QUAD)(P-T)!Q同时表!示2种类型。
IMPLICIT TYPE(ARTICAL)(A-H),CHARACTER*100(B,Q)!B同时表!示2种类型。
使用隐式类型声明在一个嵌套作用域里面所导致的变量作用域混乱问题在有关作用域之间通讯时再讨论。
7.4 数组属性
数组的概念来源于数学的向量概念,最大的特点就是数组的各个分量必须是同一种数据类型,同样的种别参数,具有同样的属性,因此数组本身作为一个数据对象,最主要的属性就只剩下它的维度,也就是它的秩。
作为一个变量的数组可以有多种形式,除了它的分量可以发生变化之外,它的维度也可以发生变化,有3种情形需要数组的维度不予固定:
● 在程序运行当中,数组所占据的存储空间不是固定的,而是可重新分配的,这意味
着该数组必定具有ALLOCATABLE属性;
● 该数组被赋予指针的属性,使得它的维度无法预先固定下来;
● 该数组本身就是一个哑元,它的维度依赖于别的变量对它的赋值情况。
因此数组本身形状的说明出现了4种形式,而数组所特有的属性,主要就是DIMENSION和ALLOCATABLE,下面分小节予以说明。
7.3.1 数组描述的4种形式
数组描述的4种形式的句法形式(R513)为:
explicit-shape-specification-list
deferred-shape-specification-list
assumed- shape-specification-list
assumed-size-specification
这四种形式分别用来描述数组在程序当中出现的四种可能情形:
● 首先是最基本的显形数组(explicit-shape arrays),即在定义数组的时候就已经给出它的形状;
● 当一个数组具有指针属性,或具有可分配属性时,它的形状就没法预先给定,需要在程序运行过程当中通过指针或分配过程予以确定,这时就需要使用待定形数组(deferred-shape arrays)的形式来加以描述;
● 当数组本身属于哑元时,它的形状就需要实元来赋予,这样就需要使用哑形数组(assumed- shape arrays)的形式来加以描述;
● 如果实元赋予一个作为哑元的数组时,只是决定它的尺度,而没有给定其他形状要素,那么就需要使用哑尺度数组(assumed-size arrays)的形式来加以描述。
下面我们将分节说明这四种数组的描述方式。
数组的描述的一般规则如下:
● 按照FORTRAN标准,数组的秩至少可以达到7,尽管一般应用环境里,秩为2或3是最常见的,但是对于一些特定的计算问题,可能需要用到非常高的维度的数组,所以一般的FORTRAN编译器都能支持远大于7的秩。
● 一个标量的秩为0。
● 待定形数组必定或者具有POINTER的属性,或者具有ALLOCATABLE的属性。
● 哑形数组和哑尺度数组必定属于哑元。
● 必须注意待定形数组和哑形数组的表示形式可能出现雷同的时候,即都是使用一个冒号表示。
7.3.2 显形数组
顾名思义,所谓显形数组就是对于数组的每一个维度都给出了具体的上下界,每个维度的显形说明的句法形式(R514)如下:
[ low-bound :] upper-bound
其中的上界(upper-bound)和下界(low-bound)为说明表达式。参见表达式。
显形数组的一般规则如下:
● 显形数组的说明列表里所给出的上下界对的数目必须与该数组的维度数目一致。
● 如果下界被省略了,则表明取默认值1。
● 上下界可以是正整数,也可以是负整数,还可以是0。
● 数组的下标范围就是在上下界之间,包括上下界本身的所有整数集合,并且上界不能小于下界,如果出现这种情况,表明下标范围为空集,或者说其相应维度的宽度为0,而且数组的尺度也为0。
● 如果上下界是以表达式的形式出现,那么可能包含变量,使得上下界的具体取值在数组所处的过程运行当中发生变化,这时,该数组必定是一个哑元,或者是一个函数结果,或者是一个动态数组。
【例7-17】 下面是主要说明数据项的声明语句:
INTEGER X(20:30,5,-10:40)
….
SUBROUTINE AAA(I,J,K)
REAL,DIMENSION(10:I+2,J)::K
….
【例7-18】 下面是主要说明属性的声明语句:
INTEGER X(20:30,5,-10:40)
….
SUBROUTINE AAA(I,J,K)
REAL K
DIMENSION K(10:I+2,J)
….
7.3.3 待定形数组
待定形数组用来表示具有指针属性和可分配属性的数组。
● 对于指针数组来说,数组的每个维度的宽度是在指针被分配或指针赋值语句被执行之后才给定的;
● 对于可分配数组来说,它的上下界只是在被分配之后才给出。
因此对于这种数组的形状说明,只能使用一个冒号,即如下的句法形式(R518):
:
待定形数组的一般规则如下:
● 待定形数组的秩等于它的说明列表当中出现的冒号的数目。
● 当待定形数组完成存储分配之后,它的上下界在ALLOCATE语句当中被确定。
● 对一个指针数组的目标数组的每个维度执行固有函数LBOUND,就能得到指针数组的相应维度的下界;同样的,对一个指针数组的目标数组的每个维度执行固有函数UBOUND,就能得到指针数组的相应维度的上界。
因此,
● 如果上下界是由指针的分配决定,那么该数组的形状就可以由用户来指定;
● 如果上下界是由指针的赋值决定,那么该数组的形状就可以有二种情形:
● 如果指针目标是一个命名全数组,那么上下界就由该数组的声明决定,或者在该数组被分配之后给出;
● 如果指针目标是一个数组片断,那么它的下界为1,而上界为所处维度的宽度。
● 如果指针数组或可分配的上下界里面包含变量,那么当变量在随后有了重定义与去定义的情形的话,上下界不受这种变化的影响。
【例7-19】 下面是主要说明数据项的声明语句:
REAL,POINTER::A( : , : ),B( : , : )
REAL,ALLOCATABLE::A( : , : )
【例7-20】 下面是主要说明属性的声明语句:
REAL A( : , : ),B( : , : )
POINTER A,B
ALLOCATABLE A
7.3.4 哑形数组
所谓哑形数组,就是一个哑元,它的形状只有在与一个实元相结合时才能定下来,哑形数组的说明句法(R517)为:
[ low-bound] :
即只是可选地给出一个下界,然后就是一个冒号,下界阙如,表示未定。
哑形数组的一般规则如下:
● 哑形数组的说明列表当中出现的冒号的个数,就等于该数组的秩。
● 下界或者明确给出,或者省略,表示下界取默认值1
展开阅读全文