简体   繁体   中英

How to simply reconstruct numbers from a buffer in little endian format

Suppose I have:

typedef unsigned long long uint64;

unsigned char data[BUF_SIZE];    

uint64 MyPacket::GetCRC()
{
  return (uint64)(data[45] | data[46] << 8 | 
         data[47] << 16 | data[48] << 24 |
         (uint64)data[49] << 32| (uint64)data[50] << 40 |
         (uint64)data[51] << 48| (uint64)data[52] << 56);
}

Just wondering, if there is an cleaner way. I tried a memcpy to an uint64 variable but that gives me the wrong value. I think I need the reverse. The data is in little endian format.

The big advantage of using the shift-or sequence is that it will work regardless if your host machine is big- or little-endian.

Of course, you would always tweak the expression. Personally, I try to join "pairs", that is two bytes at a time, then two shorts, and finally two longs, as this will help compilers to generate better code.

Well, maybe better idea is to swap order + cast?

typedef unsigned long long uint64;

unsigned char data[BUF_SIZE];    

uint64 MyPacket::GetCRC()
{
  uint64 retval;
  unsigned char *rdata = reinterpret_cast<unsigned char*>(&retval);
  for(unsigned i = 0; i < 8; ++i) rdata[i] = data[52-i];
  return retval;
}

Here's one of my own that is similar to that provided by @x13n.

uint64 MyPacket::GetCRC()
{
    int offset=45;
    uint64 crc;
    memcpy(&crc, data+offset, 8);
    //std::reverse((char*)&crc, (char*)&crc + 8); // if this was a big endian machine
    return crc;
}

Nothing much wrong with what you have there to be honest. It will work and it's quick. The thing I'd change would be to format it a little better for readability:

uint64 MyPacket::GetCRC()
{
  return (uint64) data[45]       | 
         (uint64) data[46] << 8  | 
         (uint64) data[47] << 16 | 
         (uint64) data[48] << 24 |
         (uint64) data[49] << 32 | 
         (uint64) data[50] << 40 |
         (uint64) data[51] << 48 | 
         (uint64) data[52] << 56;
}

I guess your other option would be to do it in a loop instead:

uint64 MyPacket::GetCRC()
{
   const int crcoffset = 45;
   uint64 crc = 0;

   for (int i = 0; i < 8; i++)
   {
       crc |= (uint64)data[i + crcoffset] << (i * 8);
   }
   return crc;
}

That would probably result in very similar assembly (as the compiler would probably do loop-unwinding for such a small loop) but it is a bit harder to grok in my opinion so you are better off with what you have.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM