Fortran中的陷阱-NAMELIST
1. NAMELIST简介
NAMELIST(有名列表)是一种特殊的I/O方法,它将一组变量和数值封装在一起,进行输入/输出操作。其声明形式如下:
NAMELIST /nl_group_name/ var1[,var2,...]
其中nl_group_name是有名列表的名字,var1、var2等是列表中的变量。同一个NAMELIST中可以有不同类型的变量或数组。
NAMELIST的输出语句形式如下:
WRITE(UNIT=unit,NML=nl_group_name,[...])
其中unit是数据写入的I/O单元,nl_group_name是被写的有名列表的名字。当执行WRITE语句时,列表中的所有变量名都会和其值一起按照特定的顺序输出。输出的第一项是&,然后紧跟列表的名字,然后是一系列按照"Name=Value"格式的输出值。最后,列表以一个斜杠/结束。每个数值的输出格式是由编译器自行决定的。
例如,对有名列表
NAMELIST /MYLIST/ i,j
当i=1,j=2时
执行WRITE(UNIT=*,NML=MYLIST)后,屏幕会显示
&MYLIST
I = 1,
J = 2
/
有名列表的READ语句通用形式如下:
READ(UNIT=unit,NML=nl_group_name,[...])
其中unit是将要读取数据的I/O单元,nl_group_name是被读的有名列表的名字。当执行表控有名列表的READ语句时,程序搜索带有&nl_group_name的输入文件行,它表示有名列表的开始。然后读取有名列表中的所有数值,直到碰到字符"/"终止READ。列表变量可以不出现在输入文件的有名列表中,此时READ前后这些变量的值保持不变。而且输入文件中列表变量可以出现在&nl_group_name和字符"/"间的任意一行。
使用NAMELIST可以比较方便地在程序之间传递一系列数据,省去了很多文件读写格式上的麻烦。
2. 陷阱展示
2.1 操作环境
编译器:ifort 19.0.1.144
操作系统:Ubuntu 18.04.2
2.2 文件准备
现在我们先创建一个包含NAMELIST的MODULE,将其写在namelist.f90中:
module namelist_module
implicit none
integer :: i,j
namelist /int_list/ i
end module namelist_module
注意,此时namelist_module中有i和j两个值,但是int_list中目前只有一个i。
然后写一个主程序完成NAMELIST的READ和WRITE,将其写在Pitfall.f90中:
program main
use namelist_module
implicit none
integer :: io
open(newunit=io,file='Input')
read(unit=io,nml=int_list)
write(unit=*,nml=int_list)
end program
NAMELIST的输入是通过读取文件Input完成的,输出则是直接输出到屏幕上。Input的内容为:
& int_list
i=1
/
为了方便编译,需要写一个Makefile文件,内容如下:
namelist.o : namelist.f90
ifort namelist.f90 -c
Pitfall.o : Pitfall.f90
ifort Pitfall.f90 -c
Pitfall : namelist.o Pitfall.o
ifort namelist.o Pitfall.o -o Pitfall
clean :
rm -f *.o *.mod && rm -f Pitfall
2.3 开始操作
2.3.1 程序编译
命令行输入:
make Pitfall
屏幕输出:
ifort namelist.f90 -c
ifort Pitfall.f90 -c
ifort namelist.o Pitfall.o -o Pitfall
说明程序编译正常结束。
2.3.2 程序运行
命令行输入
./Pitfall
屏幕输出:
&INT_LIST
I = 1
/
NAMELIST输出正常。
2.3.3 修改源代码与Input文件
将namelist.f90中的第4行改写为
namelist /int_list/ i,j
即namelist中多出了一个变量j。
在Input中第3行插入
j=2
即在Input中读取变量j的值。
2.3.4 重新编译程序
命令行输入:
make Pitfall
屏幕输出:
ifort namelist.f90 -c
ifort namelist.o Pitfall.o -o Pitfall
说明程序编译正常结束。注意,由于我没有修改Pitfall.f90,Pitfall.f90没有被重新编译。
2.3.5 重新运行程序
命令行输入
./Pitfall
屏幕输出:
forrtl: severe (19): invalid reference to variable in NAMELIST input, unit -129, file /home/zxli/Documents/Pitfall-in-Fortran/namelist/Input, line 3, position 2
Image PC Routine Line Source
Pitfall 00000000004441CB Unknown Unknown Unknown
Pitfall 0000000000411446 Unknown Unknown Unknown
Pitfall 0000000000402C13 Unknown Unknown Unknown
Pitfall 0000000000402B02 Unknown Unknown Unknown
libc-2.27.so 00001552E1EE0B97 __libc_start_main Unknown Unknown
Pitfall 00000000004029EA Unknown Unknown Unknown
这说明重新编译过后,程序无法正常读取新的NAMELIST中的变量j。
2.3.6 再次修改并重新运行程序
将Input中的在步骤3中添加的内容删除,再次运行程序。
命令行输入
./Pitfall
屏幕输出:
&INT_LIST
I = 1
/
这说明主程序认为NAMELIST中只有变量i。这是因为步骤4中Pitfall.f90没有被重新编译。
2.3.7 再次重新编译并运行程序
命令行输入
make clean && make Pitfall
屏幕输出:
rm -f *.o *.mod && rm -f Pitfall
ifort namelist.f90 -c
ifort Pitfall.f90 -c
ifort namelist.o Pitfall.o -o Pitfall
重新在Input第3行插入
j=2
命令行输入
./Pitfall
屏幕输出:
&INT_LIST
I = 1,
J = 2
/
此时程序正常运行。
3. 总结
当NAMELIST写在MODULE中时,修改NAMELIST的内容,但不重新编译调用了这个MODULE的代码,就会出现错误。为了解决这个问题,可以在每次修改NAMELIST后重新编译所有文件,或者在Makefile中让调用了MODULE的文件依赖写有NAMELIST的MODULE文件。
参考资料:《Fortran 95/2003 程序设计 : 第3版》,p547-549
- 让BASH,VIM美美的Powerline
- 极品三数666.cn易主,价格让人大惊!
- ui-router中使用ocLazyLoad和resolve
- rpc框架之 avro 学习 2 - 高效的序列化
- rpc框架之HA/负载均衡构架设计
- 使用Docker-Docker for Web Developers(2)
- 打造高效前端工作环境-tmuxinator
- 在Linux Mint上安装node.js和npm
- JS魔法堂:再识Number type
- (cljs/run-at (JSVM. :browser) "搭建刚好可用的开发环境!")
- (cljs/run-at (->JSVM :browser) "语言基础")
- 微博爬虫
- 电话域名受欢迎,微语言融资3000万
- 前端魔法堂——异常不仅仅是try/catch
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Linux 帮助命令及工具(tldr,man,help,info)
- Json Jolt教程
- Linux 日常操作
- 回顾|腾讯云 CFS 文件存储给 Serverless 云函数带来的业务新场景
- Apache NIFI Run Duration深入理解
- Controller services are daemons
- 动手体验JVM中Class对象的唯一性
- Java SPI机制
- Apache NIFI项目结构的类资源隔离机制
- Java类加载器
- Java反射原理
- 小谈WEB简史
- Java 常用验证方法(commons-validator,hutool)
- 类加载机制
- 使用R语言绘制string蛋白互作图