0

In my c++ program I have a structure containing four unsigned char members

struct msg
{
    unsigned char zero; unsigned char one; unsigned char two; unsigned char three;
}

and created an array of struct

msg myMsg[4] = {{0x11,0x22,0xAA,0xCC},{...},{...},{...}};

now in a function I want to return an index of this array as an unsigned int

unsigned int procMsg(int n){
  return myMsg[n]; // of course this is worng
}

a value like: 0xCCAA2211

ΦXocę 웃 Пepeúpa ツ
  • 47,427
  • 17
  • 69
  • 97
Amir-Mousavi
  • 4,273
  • 12
  • 70
  • 123
  • 1
    [typically type pun via memcpy](https://stackoverflow.com/a/51228315/1708801) – Shafik Yaghmour Nov 13 '18 at 21:12
  • Is there a reason to not do `uint32_t ival = myMsg[n].zero | (myMsg[n].one << 8) | (myMsg[n].two << 16) | (myMsg[n].three << 24)` ? – ChrisD Nov 13 '18 at 21:23
  • @ChrisD thanks a lot, actually this is the answer, well I am new to c/c++ and did not know even what to search for – Amir-Mousavi Nov 13 '18 at 21:29
  • Related: https://stackoverflow.com/q/40332770/509868 – anatolyg Nov 13 '18 at 21:40
  • Cool, I asked the question in case there was some crucial performance reason to not use all the shifts and ors. If there was then @ShafikYaghmour's answer is worth reading, but note you'd need to make sure the `struct msg` was packed into 4 bytes without any padding (although it almost always would be). – ChrisD Nov 13 '18 at 21:46
  • @ChrisD thanks for the hint, actually I am just making dummy data from what a device will send, which is promised to be correct :) – Amir-Mousavi Nov 13 '18 at 22:01
  • Why doesn't your `procMsg()` simply return a `msg`? – Ulrich Eckhardt Nov 13 '18 at 22:10
  • @UlrichEckhardt because the signature is following an API calls from legacy system – Amir-Mousavi Nov 14 '18 at 08:06

2 Answers2

1

consider this:

a message like this: {0x01, 0x01, 0x01, 0x01} can be parsed as

00000001 00000001 00000001 00000001(bin) = 16.843.009(dec)

so you just need to take every char and shift them according to its position i.e.

char0 not shifted at all,

char1 shifted 8 positions to the left (or multiply by 2^8)

char2 shifted 16 positions to the left (or multiply by 2^(8*2))

char3 shifted 24 positions to the left (or multiply by 2^(8*3))

unsigned int procMsg(Message &x)
{
    return (x.three << 24) |
           (x.two << 16) |
           (x.one << 8) |
           x.zero;
}

int main(int argc, char *argv[])
{
                         //0     1     2     3
    Message myMsg[4] = {{0x01, 0x01, 0x01, 0x01},  //00000001 00000001 00000001 00000001 = 16.843.009
                        {0xFF, 0x00, 0xAA, 0xCC},  //00000001 00000001 00000001 00000001 = 3.433.693.439
                        {0x01, 0x00, 0x00, 0x00},  //00000001 00000001 00000001 00000001 = 1
                        {0x00, 0x00, 0x00, 0x00}   //00000000 00000000 00000000 00000000 = 0
                       };

    for (int i = 0; i<4; i++)
    {
        Message x = myMsg[i];
        std::cout << "res: " << procMsg(myMsg[i]) << std::endl;
    }

    return  0;

}
ΦXocę 웃 Пepeúpa ツ
  • 47,427
  • 17
  • 69
  • 97
1

You can use shifting:

uint32_t little_endian;
uint32_t big_endian;
//...
big_endian = myMsg[0].zero << 24
           | myMsg[0].one  << 16
           | myMsg[0].two  <<  8
           | myMsg[0].three;
little_endian = myMsg[0].three << 24
                myMsg[0].two   << 16
                myMsg[0].one   <<  8
                myMsg[0].zero;

As you can see, with multi-byte integers, there are two general orderings: Big Endian and Little Endian. Big Endian has the Most Significant Byte (MSB) first. The Little Endian has Least Significant Byte (LSB) first.

In general the above method is more efficient than using a loop.

Thomas Matthews
  • 56,849
  • 17
  • 98
  • 154