0

I am using this code:

int number; //=smth
unsigned char sendBuffer[255];
sendBuffer[0] = number & 0xFF;
sendBuffer[1] = (number  >> 8) & 0xFF;
sendBuffer[2] = (number  >> 16) & 0xFF;
sendBuffer[3] = (number  >> 24) & 0xFF;

to put number in byte array sendBuffer.

My question is:

  1. Say I want to embed now two numbers in the byte array, shall I proceed like this?

    sendBuffer[0] = number & 0xFF;
    sendBuffer[1] = (number  >> 8) & 0xFF;
    sendBuffer[2] = (number  >> 16) & 0xFF;
    sendBuffer[3] = (number  >> 24) & 0xFF;
    sendBuffer[4] = number2 & 0xFF;
    sendBuffer[5] = (number2  >> 8) & 0xFF;
    sendBuffer[6] = (number2  >> 16) & 0xFF;
    sendBuffer[7] = (number2  >> 24) & 0xFF;
    

    Will this work even if number is of size say 8 or 6 bytes? (I am saying this because on some platforms the int maybe 4 bytes or 6 right? So I was thinking if the above code also works when number is 6 bytes? Further thing to note is that even if it is 6 bytes, but I only store 4 byte integer inside it, will above code work?).

    This buffer I usually store on some memory of a card and I don't have problems reading it back (e.g., endiannes etc. issues, the byte array when reading seems to come in the order I saved).

  2. Finally, how to reconstruct the integer from the byte array sendBuffer?

4
  • This is one of the cases where memcpy on POD types or primitives is allowed. Look at protobuf, Boost Serialization or Boost Spirit, though Commented Sep 24, 2013 at 9:06
  • As this is C++ you should go with std::copy (which will internally almost always use memcpy or memmove for POD types). Commented Sep 24, 2013 at 9:20
  • I didn't read your question too closely so forgive me if this is irrelevant, but perhaps std::bitset could be of use to you? Commented Sep 24, 2013 at 10:52
  • I wrote a utility for exactly this purpose as port of a project: github.com/barbu110/data-compresion/blob/master/lib/utils/… . I hope this helps Commented Feb 11, 2020 at 14:03

3 Answers 3

1

1) Yes, proceed like that. No, it only works for 4 bytes.

There is a easier, better way to do this, although it can cause endianness issues if the buffer is sent from one computer to another which uses a different architecture. Assuming you know the type of number, overlay another array on top of sendBuffer.

unsigned char sendBuffer[255];
number_type *sendBufferNum = (number_type*) sendBuffer;
sendBufferNum[0] = number;
sendBufferNum[1] = number2;

Reading a number can be done the same way.

unsigned char receiveBuffer[255];
//read values into receiveBuffer
number_type *receiverBufferNum = (number_type*) receiveBuffer;
number_type number = recieveBuffer[0];
number_type number2 = receiveBuffer[1];
Sign up to request clarification or add additional context in comments.

11 Comments

What if I use this: *(int*)(sendBuffer + pos) = some_int; ? where some_int is of known type. Say int32_t
Yup, that does effectively the same thing. Just note that the second integer will be sendBuffer+4, and the next one sendBuffer+8.
Yes I am embedding several integers using that method now, thanks.
Also I just read a bit of your post I missed the first time. "I am saying this because on some platforms the int maybe 4 bytes or 6 right?" #include<stdint> allows you to use fixed-size ints. int<size>_t and uint<size>_t, where 'size' is in bytes, will /always/ be the same size.
Yes that is why I am using int32_t. Actually my code is smth like this: *(int32_t*)(sendBuffer + 0) = some_int; *(int32_t*)(sendBuffer + 4) = some_int2; Looks ok?
|
0
  1. This only works for 32bit (4 bytes) integer. You have to write a 64bit (8 bytes) version if you are going to support large int.

  2. You can reverse the process using bitwise OR.

    #define BigEndianGetUInt32(ptr)  ( ((uint32)((uint8*)(ptr))[0]) << 24 | \  
                                       ((uint32)((uint8*)(ptr))[1]) << 16 | \  
                                       ((uint32)((uint8*)(ptr))[2]) <<  8 | \  
                                        (uint32)((uint8*)(ptr))[3]) )
    number  = BigEndianGetUInt32(sendBuffer);
    number1 = BigEndianGetUInt32(sendBuffer+4);
    

As a side note, if you're serializing data just for the same device, you could have memcpy'ed number to sendBuffer.

memcpy(sendBuffer, &number, sizeof(number));
memcpy(sendBuffer+sizeof(number), &number1, sizeof(number1));

2 Comments

what if the integer is 6 bytes, but I know I will always store only 4 byte value inside it - will my code work in such case?
If you're going to store an integer with 6 bytes (48 bits) of significant bits, you would have to use a 64 bits large integer. It's either 4 or 8 bytes, there is no middle ground.
0

Will this work even if number is of size say 8 or 6 bytes?

It works but obviously you need to add more lines to save all the bytes in the value. That's a lot of manual work which is not very extensible. Use a programmatic approach instead

auto num = number;
for (size_t i = 0; i < sizeof(number); i++, num >>= CHAR_BIT)
    sendBuffer[i] = number & 0xFF;

But why do that when you already have memcpy()? This way you need only 1 line, and even better, it can be extended to multiple values easily

memcpy(&sendBuffer[0],               number1, sizeof number1);
memcpy(&sendBuffer[sizeof(number1)], number2, sizeof number2);

Finally, how to reconstruct the integer from the byte array sendBuffer?

Easy. Just shift the bytes back

number  = (sendBuffer[3] << 24) | (sendBuffer[2] << 16) | (sendBuffer[1] << 8) | sendBuffer[0];
number2 = (sendBuffer[7] << 24) | (sendBuffer[6] << 16) | (sendBuffer[5] << 8) | sendBuffer[4];

Again, avoid tedious work like that and use a for loop

number = 0;
for (size_t i = 0; i < sizeof(number); i++)
    number = (number << 8) | sendBuffer[i];

But memcpy also works and is highly recommended

memcpy(&number, &sendBuffer[numberIndex], sizeof number);

Comments

Your Answer

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