18

I've been looking around how to convert big-endian to little-endians. But I didn't find any good that could solve my problem. It seem to be there's many way you can do this conversion. Anyway this following code works ok in a big-endian system. But how should I write a conversion function so it will work on little-endian system as well?

This is a homework, but it just an extra since the systems at school running big-endian system. It's just that I got curious and wanted to make it work on my home computer also

#include <iostream>
#include <fstream>

using namespace std;

int main()
{
   ifstream file;

   file.open("file.bin", ios::in | ios::binary);

   if(!file)
      cerr << "Not able to read" << endl;
   else
   {
      cout << "Opened" << endl;

      int i_var;
      double d_var;

      while(!file.eof())
      {
         file.read( reinterpret_cast<char*>(&i_var) , sizeof(int) );
         file.read( reinterpret_cast<char*>(&d_var) , sizeof(double) );
         cout << i_var << " " << d_var << endl;
      }
   }
   return 0;
}

Solved

So Big-endian VS Little-endian is just a reverse order of the bytes. This function i wrote seem to serve my purpose anyway. I added it here in case someone else would need it in future. This is for double only though, for integer either use the function torak suggested or you can modify this code by making it swap 4 bytes only.

double swap(double d)
{
   double a;
   unsigned char *dst = (unsigned char *)&a;
   unsigned char *src = (unsigned char *)&d;

   dst[0] = src[7];
   dst[1] = src[6];
   dst[2] = src[5];
   dst[3] = src[4];
   dst[4] = src[3];
   dst[5] = src[2];
   dst[6] = src[1];
   dst[7] = src[0];

   return a;
}
Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
starcorn
  • 8,261
  • 23
  • 83
  • 124
  • 1
    Even if you solved your endianess problem, floating point formats might vary between platforms. You cannot save floating point values binary on one platform and expect to load them on another. Is it a requirement you do this binary? – sbi Sep 29 '10 at 16:59
  • well it is not a requirement since the assignment is to be done and shown on the computers at the school. It is just my curiosity that I want to know how to read this binary file on a windows computer. – starcorn Sep 29 '10 at 17:04
  • 1
    @sbi - what platforms currently have floating point implemented in non-IEE-754? – Kos Jan 01 '11 at 20:02
  • @Kos: [not much](http://stackoverflow.com/questions/6971886/exotic-architectures-the-standard-committee-cares-about), and I believe you won't need to use them. – Yakov Galka Apr 15 '13 at 22:34
  • 1
    @Kos [Do any real-world CPUs not use IEEE 754?](http://stackoverflow.com/q/2234468/995714) – phuclv Jan 12 '16 at 09:23

5 Answers5

23

You could use a template for your endian swap that will be generalized for the data types:

#include <algorithm>

template <class T>
void endswap(T *objp)
{
  unsigned char *memp = reinterpret_cast<unsigned char*>(objp);
  std::reverse(memp, memp + sizeof(T));
}

Then your code would end up looking something like:

file.read( reinterpret_cast<char*>(&i_var) , sizeof(int) );
endswap( &i_var );
file.read( reinterpret_cast<char*>(&d_var) , sizeof(double) );  
endswap( &d_var );
cout << i_var << " " << d_var << endl;  
Dingo
  • 3,305
  • 18
  • 14
  • 1
    I have something similar, but taking the object per reference, instead of pointer. – sbi Sep 29 '10 at 18:25
4

Linux provides endian.h, which has efficient endian swapping routines up to 64-bit. It also automagically accounts for your system's endianness. The 32-bit functions are defined like this:

uint32_t htobe32(uint32_t host_32bits);           // host to big-endian encoding
uint32_t htole32(uint32_t host_32bits);           // host to lil-endian encoding
uint32_t be32toh(uint32_t big_endian_32bits);     // big-endian to host encoding
uint32_t le32toh(uint32_t little_endian_32bits);  // lil-endian to host encoding

with similarly-named functions for 16 and 64-bit. So you just say

 x = le32toh(x);

to convert a 32-bit integer in little-endian encoding to the host CPU encoding. This is useful for reading little-endian data.

 x = htole32(x);

will convert from the host encoding to 32-bit little-endian. This is useful for writing little-endian data.

Note on BSD systems, the equivalent header file is sys/endian.h

Daniel Hanrahan
  • 4,801
  • 7
  • 31
  • 44
  • 1
    Also be careful because the BSD header is *not* assembly-safe, meaning you cannot include it in any assembly files that are part of your C/C++ program. This got me because after reading Linux's `endian.h` header, I implicitly assumed all `endian.h` headers were preprocessor-only, which is wrong. Just putting this out here to avoid someone else falling in the same trap. – Thomas Jul 03 '13 at 05:39
4

You might be interested in the ntohl family of functions. These are designed to transform data from network to host byte order. Network byte order is big endian, therefore on big endian systems they don't do anything, while the same code compiled on a little endian system will perform the appropriate byte swaps.

torak
  • 5,684
  • 21
  • 25
  • is there's something similar for double? – starcorn Sep 29 '10 at 17:10
  • 1
    The way that floating point numbers are represented is more complicated (and varried) than for itegers, and I've never tried so I'm not 100% sure. However, assuming that the floating point representations on the two machines match (except for endianness) the article that Bryan linked to suggests it should be possible. – torak Sep 29 '10 at 17:19
2

It is good to add that MS has this supported on VS too check this inline functions:

  • htond
  • htonf
  • htonl
  • htonll
  • htons
Mahmoud Fayez
  • 3,398
  • 2
  • 19
  • 36
2

Assuming you're going to be going on, it's handy to keep a little library file of helper functions. 2 of those functions should be endian swaps for 4 byte values, and 2 byte values. For some solid examples (including code) check out this article.

Once you've got your swap functions, any time you read in a value in the wrong endian, call the appropriate swap function. Sometimes a stumbling point for people here is that single byte values do not need to be endian swapped, so if you're reading in something like a character stream that represents a string of letters from a file, that should be good to go. It's only when you're reading in a value this is multiple bytes (like an integer value) that you have to swap them.

Bryan
  • 2,068
  • 2
  • 15
  • 18
  • actually i get confused since there's alot of different swap. On that article it was swaps for short, long and float. Will any of those swaps work for the datatypes i'm working with? – starcorn Sep 29 '10 at 17:01
  • The solutions are dependent on the size of your data value. If you have a 2 byte value, you use `ShortSwap()`, if you have a 4 byte value `LongSwap().` The `FloatSwap()` in the example there is kind of pointless, except in that there's a logical difference between float storage and long storage... The LongSwap will still work correctly on a 4 byte float though. What you did in your posted solution up top is effectively the same thing for an 8 byte value. – Bryan Sep 29 '10 at 19:08
  • The link is 404 now! – Victor Paléologue Sep 15 '17 at 15:12
  • So go way back: https://web.archive.org/web/20071113102719/http://www.gamedev.net:80/reference/articles/article2091.asp – Robert Hijmans Nov 28 '17 at 02:52