0

I have FORTRAN 77 binary file (created on Sun Sparc machine,big endian). I want to read it on my little endian machine. I have come across this

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

Paul has written these macros for C or C++, but I do not understand what they really do.

#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)

I know that every record of the file contains contains

x,y,z,t,d,i

i is integer*2,all other variables are real*4. First 512 bytes hexdump

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

My code to read file

#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;

}

}

I got two errors r.cc: In function ‘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;
8
  • The macros are dangerous and use some outdated techniques like relying on short having 16 bits. Commented Jun 20, 2016 at 13:27
  • 1
    C and C++ are different languages! Your code looks like C, pick one language! Commented Jun 20, 2016 at 13:29
  • This is why human readable formats are far preferable. Commented Jun 20, 2016 at 14:05
  • Your binary file also has 64-bit big-endian record lengths before and after the data that you will have to skip over. FWIW, Intel Fortran supports reading such files with its CONVERT="BIG_ENDIAN" option. Commented Jun 20, 2016 at 16:52
  • @SteveLionel ok,THANKS will try latter. Commented Jun 20, 2016 at 17:15

1 Answer 1

2

If you're reading the file on a linux machine, there are some library functions provided for this purpose in the endian.h header (documentation here). To convert a 16-bit integer to host order (little-endian in your case):

uint16_t hostInteger = be16toh(bigEndianIntegerFromFile);

For floats, you can do something similar but incorporate reinterpretation:

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

Or, if you read it as an unsigned int in the first place, you don't need the inner reinterpret_cast:

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

UPDATE: Given your code, you could read the file by inserting this between your fclose and free calls:

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
    ...
}
Sign up to request clarification or add additional context in comments.

4 Comments

Sure, he's not using C++ streams. You can call it C not C++ if you want, but I don't think it invalidates his question. He could very well have code elsewhere that is much more C++, I'm not going to judge.
@MikiBelavista - I edited the code somewhat, you have to do reinterpret_cast on pointers rather than values. However, the first compile error was just a missing bracket, you should at least try to fix them yourself!
@Smeeheey Thanks for help,I have changed a little bit,still got two errors.
Change constexpr to const

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.