linux - Fortran 77 从旧的 sun 机器读取未格式化的序列数据

标签 linux fortran gfortran fortran77 sun

我正在将一个旧的数学模型(1995 年到 2000 年之间)移植到当前的 Linux 机器上。为此,我调整了所有 makefile,如下所示:

FORTRAN  = gfortran # f90 -f77 -ftrap=%none
OPTS     = -O -u -lgfortran -g -fconvert="big-endian" # -O -u
NOOPT    = 
LOADER   = gfortran #f90
LOADOPTS = #-lf77compat

和:

SYSFFLAGS   = -O0 -u -g -fconvert="big-endian" # -f77=input
SYSCFLAGS   = -DX_WCHAR
SYSLDFLAGS  =  
SYSCPPFLAGS = -DSYS_UNIX -DCODE_ASCII -DCODE_IEEE # -DSYS_Sun
SYSAUTODBL  = -fdefault-real-8 #-r8
SYSDEBUG    = -g
SYSCHECK    = -C 
LINKOPT =
CPPOPT  = 

SHELL       = /bin/sh
CC      = cc

FC      = gfortran # f90
LD      = gfortran # f90
AR      = ar vru
RM      = rm -f
CP      = cp
MV      = mv -f
LN      = ln -s

所以我替换了所有过时的编译器/选项以便能够编译代码。之后,它生成没有错误的二进制文件。请注意,# 符号后面的所有选项都是 Makefile 中的原始选项。

因此,在运行程序时,无法读取样本数据。 IMO 这些文件是在 Sun 机器上以未格式化序列模式创建的。以下十六进制转储属于我需要读取的文件。

0000000: 0000 0400 2020 2020 2020 2020 2020 2020  ....
0000010: 3930 3130 7465 7374 2d63 3031 2020 2020  9010test-c01
0000020: 2020 2020 4741 5520 2020 2020 2020 2020      GAU
0000030: 2020 2020 2020 2020 2020 2020 2020 2020
0000040: 2020 2020 2020 2020 2020 2020 2020 2020
0000050: 2020 2020 2020 2020 2020 2020 2020 2020
...
...
0000390: 2020 2020 2020 2020 2020 2020 2020 2020
00003a0: 2020 2020 2020 2020 2020 2020 2020 2020
00003b0: 2020 2020 3139 3936 3037 3232 2032 3030      19960722 200
00003c0: 3434 3920 4147 434d 352e 3420 2020 2020  449 AGCM5.4
00003d0: 2020 2020 3230 3030 3036 3134 2031 3230      20000614 120
00003e0: 3831 3720 6869 726f 2020 2020 2020 2020  817 hiro
00003f0: 2020 2020 2020 2020 2020 2020 2020 2034                 4
0000400: 3039 3630 0000 0400 0002 8000 bef7 21f3  0960..........!.
0000410: bf3c 55ab bf7a 8f71 bf99 e26a bfb2 db4e  .<U..z.q...j...N
0000420: bfc7 425f bfd6 64b1 bfdf d44f bfe3 6a43  ..B_..d....O..jC

分析代码后,可以读取到0000410行。在 0002 8000 标记后无法继续。下面显示的源代码实际上是在读取这个文件。

...
*   [INPUT] 
INTEGER    IFILE
CHARACTER  HITEM  *(*)                    !! name for identify
CHARACTER  HDFMT  *(*)                    !! data format
*
*   [ENTRY INPUT] 
REAL * 8   TIME1                          !! time
REAL * 8   TIME2                          !! time
REAL*8     DMIN
REAL*8     DMAX
REAL*8     DIVS
REAL*8     DIVL
INTEGER    ISTYPE
INTEGER    JFILE                          !! output file No.
INTEGER    IMAXD
INTEGER    JMAXD
*
*   [WORK] 
REAL * 8   DDATA ( NGDWRK )
REAL * 4   SDATA ( NGDWRK )
*
*   [INTERNAL WORK] 
INTEGER    I, J, K, IJK, IJKNUM, IERR
...
...
READ ( IFILE, IOSTAT=IEOD ) HEAD
...
...
...
DO 2150 IJK = 1, IJKNUM              
    READ ( IFILE, END=2150 ) SDATA(IJK)
    WRITE (6,*) ' IGTIO::GTZZRD: iteration=', IJK, SDATA(IJK)
2150 CONTINUE

为了轻松调试循环,我将上面的循环替换掉了。原始的是隐含的。

READ ( IFILE, IOSTAT=IEOD)
&              (SDATA(IJK), IJK=1, IJKNUM )

循环的输出是:

IGTIO::GTZZRD: iteration=           1 -0.48268089    
IGTIO::GTZZRD: iteration=           2  1.35631564E-19
IGTIO::GTZZRD: iteration=           3 -0.48142704    
IGTIO::GTZZRD: iteration=           4  1.35631564E-19
IGTIO::GTZZRD: iteration=           5   244.25270    
IGTIO::GTZZRD: iteration=           6  1.35631564E-19
IGTIO::GTZZRD: iteration=           7   983.87988    
IGTIO::GTZZRD: iteration=           8  1.35631564E-19
IGTIO::GTZZRD: iteration=           9  1.59284362E-04
IGTIO::GTZZRD: iteration=          10  1.35631564E-19
IGTIO::GTZZRD: iteration=          11   0.0000000  
---error here---

我肯定迷失在这方面,所以任何帮助表示赞赏。

最佳答案

这是怎么回事 - 首先这绝对是一个 Big Enfian 文件。 前4个字节

00000400

是big end 4 byte integer 1024,也就是你第一条记录的长度。 这与 HEAD 的长度一致(根据评论) 现在请注意,00000400 在字节位置 1024+4 处重复(十六进制转储行 400),正如您对 Fortran 未格式化文件所期望的那样......到目前为止一切顺利。

现在接下来的 4 个字节

0002 8000

开始第二条记录。 (编辑更正错误)这是 163840 (2*16^4+8*16^3) 您应该会发现它在十六进制转储中的位置 1024+8+163840+4 处重复出现。 (我认为应该是 028400 行。)

问题在于:在您的代码中,您正在将 160 KB 的记录读取到一个 4 字节的变量中,然后继续读取下一条记录。我猜你看到的是交替出现的 10^-19,因为其他所有记录都是字符类型的。

在未格式化的 fortran 中,您必须一次读取整个记录 - 尝试读取整个数组(没有循环......)

READ ( IFILE )SDATA

假设 sdata 的大小当然可以容纳 160 kb。 (例如真实*4(40960))

关于linux - Fortran 77 从旧的 sun 机器读取未格式化的序列数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21117559/

相关文章:

fortran - Fortran PURE FUNCTION 中局部变量的声明和初始化

fortran - openmp 长指令列表 fortran77 的语法

fortran - 编译 DISLIN gfortran

debugging - 如何在 idb(intel 编译器调试器)中对 fortran 可执行文件使用break命令?

multithreading - Fortran 基本函数与基本子例程

algorithm - Fortran 冒泡排序算法

linux - 禁用 TCP 延迟 ACK

linux - 在 Linux 上获取输入插入符号周围的文本

linux - Windows 和 Linux 下路径名的语法分别是什么?

linux - 维护子 shell 输出中的换行符