Big Endian and Little Endian for files in C ++

I am trying to write some processor independent code to write some big endian files. I have an example code below and I can not understand why it does not work. All he has to do is let the byte store each byte of data one by one in a large trailing order. In my real program, I will then write a separate byte to the file, so I get the same byte order in the file, regardless of the processor architecture.

#include <iostream> int main (int argc, char * const argv[]) { long data = 0x12345678; long bitmask = (0xFF << (sizeof(long) - 1) * 8); char byte = 0; for(long i = 0; i < sizeof(long); i++) { byte = data & bitmask; data <<= 8; } return 0; } 

For some reason, the byte always has a value of 0. This confuses me, I look at the debugger and see this:

data = 00010010001101000101011001111000 bitmask = 111111110000000000000000000000000000

I would think that the data and mask would give 00010010, but it just does byte 00000000 every time! How can he be? I wrote the code for a small serial number and it works fine, see below:

 #include <iostream> int main (int argc, char * const argv[]) { long data = 0x12345678; long bitmask = 0xFF; char byte = 0; for(long i = 0; i < sizeof(long); i++) { byte = data & bitmask; data >>= 8; } return 0; } 

Why does the little endian work and the big endian not? Thanks for any help :-)

+4
source share
4 answers

In your example, the data is 0x12345678.

So your first assignment to a byte:

 byte = 0x12000000; 

which does not fit in bytes, so it is truncated to zero.

to try:

 byte = (data & bitmask) >> (sizeof(long) - 1) * 8); 
+2
source

You must use the standard ntohl() functions for this as well. They work with variables of an explicit size (i.e. uint16_t and uin32_t ), and are not specific to the long compiler, which is necessary for portability.

Some platforms provide 64-bit versions in <endian.h>

+6
source

You will mix everything up.

 #include <iostream> int main (int argc, char * const argv[]) { long data = 0x12345678; int shift = (sizeof(long) - 1) * 8 const unsigned long mask = 0xff; char byte = 0; for (long i = 0; i < sizeof(long); i++, shift -= 8) { byte = (data & (mask << shift)) >> shift; } return 0; } 

Now I would not recommend you to do so. I would recommend writing some good conversion functions instead. Many compilers have built-in functions. That way, you can write your functions to make it a complicated way, and then switch them to just go to the compiler when you figure out what it is.

 #include <tr1/cstdint> // To get uint16_t, uint32_t and so on. inline uint16_t to_bigendian(uint16_t val, char bytes[2]) { bytes[0] = (val >> 8) & 0xffu; bytes[1] = val & 0xffu; } inline uint32_t to_bigendian(uint32_t val, char bytes[4]) { bytes[0] = (val >> 24) & 0xffu; bytes[1] = (val >> 16) & 0xffu; bytes[2] = (val >> 8) & 0xffu; bytes[3] = val & 0xffu; } 

This code is simpler and more understandable than your loop. It is also faster. And finally, it is recognized by some compilers and automatically turns into a byte exchange operation, which is required for most processors.

+1
source

because you mask the top byte from an integer, and then don't shift it back 24 bits ...

Change your loop to:

 for(long i = 0; i < sizeof(long); i++) { byte = (data & bitmask) >> 24; data <<= 8; } 
0
source

Source: https://habr.com/ru/post/1299728/


All Articles