fortran早期为了便于书写,提供了隐式类型默认规则。如果程序中没有写implicit none,编译器会根据变量名首字母自动推断类型。
- 当变量名以i、j、k、l、m、n开头时,默认是integer。
- 变量名以其他字母开头时,默认是real。
自动推断类型的方式确实能让旧代码少写大量声明,但也容易把拼写错误悄然变成新变量。再加上随着计算机应用的广泛发展,需用代码提高可读性、可维护性、可复用性,便默契的使用语义化命名。隐式声明天然与语义化命名冲突,因此现代fortran代码通常在单元开始写implicit none。
先看一段不推荐但能说明规则的代码。
program implicitTypeDefaultRuleDemo
! 本例故意不写implicit none,用来观察fortran默认隐式类型规则。
! 1.当变量名以i、j、k、l、m、n开头时,默认是integer类型。
! 2.变量名以其他字母开头时,默认是real类型。
! 注意:这条规则会和语义化命名发生冲突,也会让拼写错误更难被发现。
moleculeCount=6.8 ! m开头,默认是integer;6.8会先转换成6后再存储。
atomCount=moleculeCount*3.0 ! a开头,默认是real;右侧表达式结果存入real变量。
ionCount=2.5 ! i开头,默认是integer;2.5会先转换成2后再存储。
nStep=10 ! n开头,默认是integer;适合保存步数。
totalAtomCount=atomCount+ionCount ! t开头,默认是real;表示正确的原子总数。
totlaAtomCount=totalAtomCount+1.0 ! 拼写错误:totlaAtomCount是新real变量,不会报错。
print *, "隐式类型默认规则:"
print *,"moleculeCount=",moleculeCount
print *,"atomCount=",atomCount
print *,"ionCount=",ionCount
print *,"nStep=",nStep
print *,"totalAtomCount=",totalAtomCount
print *,"totlaAtomCount=",totlaAtomCount
end program implicitTypeDefaultRuleDemo
这段程序中没有任何显式变量声明,但几乎所有fortran编译器都能通过编译。
编译运行
(base) hong@hongdeMacBook-Pro 005.implicit-typing % gfortran exampleImplicitTyping.f90
(base) hong@hongdeMacBook-Pro 005.implicit-typing % ./a.out
隐式类型默认规则:
moleculeCount= 6
atomCount= 18.0000000
ionCount= 2
nStep= 10
totalAtomCount= 20.0000000
totlaAtomCount= 21.0000000
(base) hong@hongdeMacBook-Pro 005.implicit-typing %
- moleculeCount从语义看是“分子数量”,似乎应该是整数数量,编译器允许其被赋值为6.8,但会把它转换成integer,只保留6。真实程序里这种行为很危险。
- ionCount以i开头,默认也是integer,所以2.5会变成2。
- totlaAtomCount是totalAtomCount的拼写错误,但因为没有implicit none,它会被当成另一个新变量,程序不会立刻报错。
还有一种可能更危险的是拼写错误,在这段代码中,我本想更新totalAtomCount,却误写成了totlaAtomCount。
! 仍然不存在implicit none的片段
totalAtomCount=atomCount+ionCount ! t开头,默认是real;表示正确的原子总数。
totlaAtomCount=totalAtomCount+1.0 ! 拼写错误:totlaAtomCount是新real变量,不会报错。
由于没有implicit none,编译器会把totlaAtomCount看作另一个合法变量,而不是拼写错误。程序能编译,结果却违反了我的本意。
推荐写法是明确关闭隐式类型,并声明每个变量。
program implicitTypeDefaultRuleWithImplicitNoneDemo
implicit none
real :: moleculeCount
real :: atomCount
real :: ionCount
integer :: nStep
real :: totalAtomCount
moleculeCount=6.8
atomCount=moleculeCount*3.0
ionCount=2.5
nStep=10
totalAtomCount=atomCount+ionCount
print *,"此为implicit none版本"
print *,"moleculeCount=",moleculeCount
print *,"atomCount=",atomCount
print *,"ionCount=",ionCount
print *,"nStep=",nStep
print *,"totalAtomCount=",totalAtomCount
end program implicitTypeDefaultRuleWithImplicitNoneDemo
假设在这段推荐写法中写错了变量名,比如有一条新语句totlaAtomCount=totalAtomCount+1.0,编译器会直接报错Symbol ‘totlaatomcount’ at (1) has no IMPLICIT type,我会在错误代码分类中详解——不同编译器检查错误的报错与解决。也就是说,implicit none会把拼写问题提前变成编译期错误,相较于运行后才发现结果不对,会安全得多。
知识点总结:
- 默认隐式类型规则是:I到N开头为integer,其余字母开头为real。
- 隐式类型规则是历史遗留便利,并非现代代码的好习惯,只需掌握,不荐使用。
- 现代fortran建议每个程序单元都写implicit none。
- implicit none能帮助编译器发现未声明变量和拼写错误。