但没有编译器支持 24 位的整数类型。而有很多数据却恰恰采用了 24 位整型来存储。对于这种数据,我们需要进行一定的技巧和转换来实现读取。
最直接的办法,是通过内存里的延展,使其读取后,延展为 32 位的整型,并在内存中后续参与计算。
程序运行如下,将 e5ac23 这个 24 位数据写入 t.bin,并读出成 2338021
第一步:
为了能利用 stream 流文件读写,我们定义一个大小为 4 的字符数组 str,取其片段 str(1:3) 进行读取,这样就可以保证读取的是 24 位数据。如果您读取的数据是大端(big-endian)的,则更改为 str(3:1:-1) 反向读取即可。
第二步:
利用 transfer 函数,把 str 字符数组,直接转换成 32 位整型 n 。注意 transfer 函数的作用是强制转换,而不是像内部文件转换那样,考虑字符串代表的数字意义。
第三步:
由于 24 位数据,最高位第24位,表示正负。而直接转换成 32 位后,不能再具有正负的意义。因此,我们需要把 24 位数据左移 8 位,可以利用 ishft 函数实现。
左移可以确保正负号归位。但同时会令整型数值的绝对值增加 2**8 倍。因此左移后需要除以 2**8。
如果关于位操作比较难理解。那么也可以理解这句纯数字计算的算式:
if ( n > (2**23-1) ) n = n - 2**24
其含义是:如果 n 的大小超过了 24 位数据正半部分的上限,就令其减少 2**24 。
这样做的原因是 24 位扩展到32位之后,由于高位为零,始终是正数。这相当于把 24 位数据可以表达的范围由 0 至 2**24 更改到 -2**23 至 2**23-1 (这样做的前提是 str(4) = char(0) ,即高位初值为 0)
代码如下:
Program www_fcode_cn Implicit None Character :: str(4) Integer :: n Open( 12 , File = "t.bin" , access='stream' , form='unformatted' ) Read( 12 ) str(1:3) !//如果是大端,则 str(3:1:-1) n = transfer( str , n ) n = ishft( n , 8 ) / 2**8 ! if ( n > (2**23-1) ) n = n - 2**24 !如果上句不容易理解,也可以理解此句代码 write(*,'(g0)') n End Program www_fcode_cn