c++ - 如何用 C 或 C++ 读取 FORTRAN 二进制文件?

标签 c++ c binary fortran

我有 FORTRAN 77 二进制文件(在 Sun Sparc 机器上创建,大端)。我想在我的小端机器上阅读它。我遇到过这个

http://paulbourke.net/dataformats/reading/

Paul 已经为 C 或 C++ 编写了这些宏,但我不明白它们的真正作用。

#define SWAP_2(x) ( (((x) & 0xff) << 8) | ((unsigned short)(x) >> 8) )
#define SWAP_4(x) ( ((x) << 24) | (((x) << 8) & 0x00ff0000) | \
         (((x) >> 8) & 0x0000ff00) | ((x) >> 24) )
#define FIX_SHORT(x) (*(unsigned short *)&(x) = SWAP_2(*(unsigned short *)&(x)))
#define FIX_LONG(x) (*(unsigned *)&(x) = SWAP_4(*(unsigned *)&(x)))
#define FIX_FLOAT(x) FIX_LONG(x)

我知道文件的每条记录都包含

x,y,z,t,d,i

i 是整数*2,所有其他变量都是实数*4。 前 512 字节十六进制转储

0000000 0000 1800 0000 0000 0000 0000 0000 0000
0000010 0000 0000 0000 0000 ffff ffff 0000 1800
0000020 0000 1800 003f 0000 0000 0000 233c 0ad7
0000030 0000 0000 233c 0ad7 0000 0100 0000 1800
0000040 0000 1800 803f 0000 0000 0000 233c 0ad7
0000050 0000 0000 233c 0ad7 0000 0100 0000 1800
0000060 0000 1800 c03f 0000 0000 0000 233c 0ad7
0000070 0000 0000 233c 0ad7 0000 0100 0000 1800
0000080 0000 1800 0040 0000 0000 0000 233c 0ad7
0000090 0000 0000 233c 0ad7 0000 0100 0000 1800
00000a0 0000 1800 2040 0000 0000 0000 233c 0ad7
00000b0 0000 0000 233c 0ad7 0000 0100 0000 1800
00000c0 0000 1800 4040 0000 0000 0000 233c 0ad7
00000d0 0000 0000 233c 0ad7 0000 0100 0000 1800
00000e0 0000 1800 6040 0000 0000 0000 233c 0ad7
00000f0 0000 0000 233c 0ad7 0000 0100 0000 1800
0000100 0000 1800 8040 0000 0000 0000 233c 0ad7
0000110 0000 0000 233c 0ad7 0000 0100 0000 1800
0000120 0000 1800 9040 0000 0000 0000 233c 0ad7
0000130 0000 0000 233c 0ad7 0000 0100 0000 1800
0000140 0000 1800 a040 0000 0000 0000 233c 0ad7
0000150 0000 0000 233c 0ad7 0000 0100 0000 1800
0000160 0000 1800 b040 0000 0000 0000 233c 0ad7
0000170 0000 0000 233c 0ad7 0000 0100 0000 1800
0000180 0000 1800 c040 0000 0000 0000 233c 0ad7
0000190 0000 0000 233c 0ad7 0000 0100 0000 1800
00001a0 0000 1800 d040 0000 0000 0000 233c 0ad7
00001b0 0000 0000 233c 0ad7 0000 0100 0000 1800
00001c0 0000 1800 e040 0000 0000 0000 233c 0ad7
00001d0 0000 0000 233c 0ad7 0000 0100 0000 1800
00001e0 0000 1800 f040 0000 0000 0000 233c 0ad7
00001f0 0000 0000 233c 0ad7 0000 0100 0000 1800
0000200

读取文件的代码

#include <endian.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

int main() 
{
    FILE *file;
    char *buffer;
    char *rec;
    long fileLen;

    file = fopen("rec.in", "rb");


    fseek(file, 0, SEEK_END);
    fileLen=ftell(file);
    fseek(file, 0, SEEK_SET);

    buffer=(char *)malloc(fileLen+1);

    fread(buffer, fileLen, 1, file);
    fclose(file);
    free(buffer);

char *curr = buffer;
char *end = buffer + fileLen;

constexpr int LINE_SIZE = sizeof(float)*5 + sizeof(uint16_t); //based upon your "x,y,z,t,d,i" description

while(curr < end) {
    uint32_t temp = be32toh(*reinterpret_cast<uint32_t*>(*curr));
    float x = *reinterpret_cast<float*>(&temp);

    temp = be32toh(*reinterpret_cast<uint32_t*>(*(curr+sizeof(float))));
    float y = *reinterpret_cast<float*>(&temp);

    temp = be32toh(*reinterpret_cast<uint32_t*>(*(curr+2*sizeof(float))));
    float z = *reinterpret_cast<float*>(&temp);

    temp = be32toh(*reinterpret_cast<uint32_t*>(*(curr+3*sizeof(float))));
    float t = *reinterpret_cast<float*>(&temp);

    temp = be32toh(*reinterpret_cast<uint32_t*>(*(curr+4*sizeof(float))));
    float d = *reinterpret_cast<float*>(&temp);

    uint16_t i = be16toh(*reinterpret_cast<uint16_t*>(*(curr+5*sizeof(float))));

    curr += LINE_SIZE;

}

}

我有两个错误 r.cc: 在函数‘int main()’中:

r.cc:29:1: error: ‘constexpr’ was not declared in this scope
 constexpr int LINE_SIZE = sizeof(float)*5 + sizeof(uint16_t); //based upon your "x,y,z,t,d,i" description
 ^
r.cc:49:13: error: ‘LINE_SIZE’ was not declared in this scope
     curr += LINE_SIZE;

最佳答案

如果您在 Linux 机器上读取文件,endian.h header (文档 here)中提供了一些用于此目的的库函数。将 16 位整数转换为主机顺序(在您的情况下为小端):

uint16_t hostInteger = be16toh(bigEndianIntegerFromFile);

对于 float ,你可以做类似的事情,但要结合重新解释:

float hostFloat = reinterpret_cast<float>(be32toh(reinterpret_cast<uint32_t>(bigEndianFloatFromFile)));

或者,如果您首先将其作为 unsigned int 读取,则不需要内部 reinterpret_cast:

float hostFloat = reinterpret_cast<float>(be32toh(bigEndianUint32FromFile));

更新:根据您的代码,您可以通过在 fclosefree 调用之间插入此代码来读取文件:

char *curr = buffer;
char *end = buffer + fileLen;

constexpr int LINE_SIZE = sizeof(float)*5 + sizeof(uint16_t); //based upon your "x,y,z,t,d,i" description

while(curr < end) {
    uint32_t temp = be32toh(*reinterpret_cast<uint32_t*>(*curr));
    float x = *reinterpret_cast<float*>(&temp);

    temp = be32toh(*reinterpret_cast<uint32_t*>(*(curr+sizeof(float))));
    float y = *reinterpret_cast<float*>(&temp);

    temp = be32toh(*reinterpret_cast<uint32_t*>(*(curr+2*sizeof(float))));
    float z = *reinterpret_cast<float*>(&temp);

    temp = be32toh(*reinterpret_cast<uint32_t*>(*(curr+3*sizeof(float))));
    float t = *reinterpret_cast<float*>(&temp);

    temp = be32toh(*reinterpret_cast<uint32_t*>(*(curr+4*sizeof(float))));
    float d = *reinterpret_cast<float*>(&temp);

    uint16_t i = be16toh(*reinterpret_cast<uint16_t*>(*(curr+5*sizeof(float))));

    curr += LINE_SIZE;

    ...
    //do something with these values
    ...
}

关于c++ - 如何用 C 或 C++ 读取 FORTRAN 二进制文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37921714/

相关文章:

c++ - 如何计算编辑控件中的总数 - Visual MFC

c++ - linux flex gcc 编译失败,出现 `undefined reference to ` TclReError'`

c - 调整图像二进制大小

c++ - 我正在尝试对运算符 '+'进行二进制重载,但输出错误,我不明白为什么?

javascript - 分区 N,其中零件的数量和每个零件都是 2 的幂,并且零件大小和数量受到限制

c++ - 如何将 "\u002f"转换为 "/"(在 C++ 中)?

c++ - MATLAB:来自不同类的 OOP 调用函数

c++ - 将 shared_ptr 保存到类中的实现的设计模式和优点是什么?

c - 带 ioctl 的 48 位和 28 位 ATA 命令

c - 是在函数内部重新声明结构体还是将其声明为静态并每次都设置为 0 更好?