Please explain how to use the bit shift to get one unsigned int from the four unsigned char variables, then do the opposite.

    4 answers 4

    Consistently in the lower part of the int we put the next byte and shift left by 8 bits. To put 1 byte in the lower part, use the logical OR:

     unsigned char c1=5,c2=10,c3=98,c4=67; unsigned int I; I=c4; // c4 в младших 8и битах, остальные 0 I<<=8; // Сдвигаем int влево на 8 бит. Младшие 8 бит становятся 0, c4 становится в 9-16 битах. I|=c3; // Логическое ИЛИ заменяет 0 биты на те, что в байте c3 I<<=8; I|=c2; I<<=8; I|=c1; // Аналогично кладем остальные байты 

    For the reverse action, we shift the int so that the byte we need is the youngest and we mask the remaining bits with the logical AND:

     c1=I & 0xFF; c2=(I>>8) & 0xFF; c3=(I>>16) & 0xFF; c4=(I>>24) & 0xFF; 

    Just follow the order of bytes , on different architectures of the number in the int taken to put in different ways.

    • one
      What's the difference in which order the bytes are stored ( BIG_ENDIAN / LITTLE_ENDIAN )? This is responsible only for the order in which the bytes in the machine’s memory are represented, and when working with int it doesn’t matter (bytes always unfold in the same order), we don’t impose a variable of type int on any memory area at its address . Is not it so? - StateItPrimitive
    • This is just in case a remark, but I don’t know what happens next with this int. Maybe it will be decided to write to the file as a ready int and will expect a certain order - Mike
    • Okay, then the question is removed. Just reading the answer, I began to doubt that it responds only to the order of the representation of the bytes in the memory of the machine :) - StateItPrimitive
    • @Mike Do you need to perform the & 0xFF operation? You can just (unsigned char)(I>>8) , etc. And although not a stupid compiler will generate the same code in both cases, I'm still not sure that all compilers are not stupid and will understand that bitwise AND you can not do. - Zealint
    • @ ArtyomKaravaev I'm afraid not to do it. how the compiler will understand direct type casting from int to char, which of the bytes will take on litle and big endian platforms. Although, on the other hand, it will guess if you take the right after & ... maybe you don’t need it - Mike

    If you need to do only such a packing / unpacking operation, I can offer it at all without using bit operations.

     unsigned int UI = 0x12345678; char *CC = (char *)(&UI); for (int i=3;i>=0;i--) cout << (int)CC[i]<<" "; unsigned char NC[4] = {120,86,52,18}; unsigned int TI = *(unsigned int *)(NC); cout << TI; 

    The idea is based on an explicit pointer conversion. https://ideone.com/1P4tfc running example.

    • four
      This is UB. *(unsigned int *)(NC) violates both aliasing rules and alignment. - Abyx
    • 2
      @Abyx, at least on x86 in g ++, it will work (and it's hard to assume that there is a real compiler that breaks the alignment here (here in this code) alignment (why would it insert a padding in 1, 2 or 3 bytes in stack in front of NC [4]?)) A strict aliasing (despite the warnings of the standard) in this case, imho brute force. - avp

    For example, like this:

     int main() { unsigned char ch1 = 0x1; unsigned char ch2 = 0x2; unsigned char ch3 = 0x3; unsigned char ch4 = 0x4; unsigned int value = ch1; value <<= 8; value |= ch2; value <<= 8; value |= ch3; value <<= 8; value |= ch4; } 

    Or a slightly more general solution:

     #include <array> const size_t BYTE_COUNT_IN_INT = 4; const size_t BITS_COUNT_IN_BYTE = 8; unsigned int getIntFromCharsArray(const std::array<unsigned char, BYTE_COUNT_IN_INT>& charsArray) { unsigned int result = charsArray[0]; for (size_t i = 1; i <= BYTE_COUNT_IN_INT - 1; ++i) { result <<= BITS_COUNT_IN_BYTE; result |= charsArray[i]; } return result; } std::array<unsigned char, BYTE_COUNT_IN_INT> getCharsArrayFromInt(unsigned int value) { std::array<unsigned char, BYTE_COUNT_IN_INT> result; for (size_t i = 0; i <= BYTE_COUNT_IN_INT - 1; ++i) { result[BYTE_COUNT_IN_INT - i - 1] = value; value >>= BITS_COUNT_IN_BYTE; } return result; } int main() { const std::array<unsigned char, BYTE_COUNT_IN_INT> charsArray = { 0x1, 0x2, 0x3, 0x4 }; unsigned int intFromCharsArray = getIntFromCharsArray(charsArray); auto charsArrayFromInt = getCharsArrayFromInt(intFromCharsArray); } 
    • 3
      do not write void main() , this is not correct. - Abyx
    • @Abyx does not need to write 'wrong', this is wrong. :) Pro 'void' agree, legacy MS. - αλεχολυτ

    I will add. If you need exactly the conversion and you can not use bit shifts, then the simplest solution through the union :

     union converter { unsigned int number; unsigned char bytes[4]; }; 

    Number in bytes:

     converter c; c.number = 123; // c.bytes[0] == 0xD2 // c.bytes[1] == 0x04 // c.bytes[2] == 0x00 // c.bytes[3] == 0x00 

    Bytes to number:

     converter c; c.bytes[0] = 1; c.bytes[1] = 2; c.bytes[2] = 3; c.bytes[3] = 4; // c.number == 0x04030201 (big-endian) 
    • one
      Violation strict aliasing = UB. - VladD