Suppose there is a 64 bit variable:

unsigned long long a = 0x12345671FBC00045; 

How to write in another 16-bit variable b second 16 bits from the variable a , so as to get the result 0x5671 ? For example:

 unsigned short int b = 0x5671; 

How generally to select any quantity of bits from a variable and to write them in another?

    4 answers 4

     b = (a & 0x0000FFFF00000000) >> 32; 

    Search keywords are bitmasks and shifts. Read - bit operations .

    • Thanks for the answer, it helped a lot !!! - kristianmelson
    • 3
      Or even (a >> 32)&0xFFFF :) - Harry
    • in this case, even the mask does not need to impose. But in fact there are a dozen ways to select it all. - KoVadim
    • The mask is ( 0xFFFF ) only it is superimposed after the shift. - 伪位蔚蠂慰位蠀蟿
    • If you use C ++, you can see std :: bitset - JK_Action

    You can write a function that will provide a mask to select any number of contiguous bits from a number, starting from a given position.

    Below is a demonstration program containing such a function.

     #include <iostream> #include <iomanip> unsigned long long get_mask( size_t pos, size_t n ) { return ~( ~0ull << n ) << pos; } int main() { unsigned long long a = 0x12345671FBC00045; unsigned short b; std::cout << std::hex << a << std::endl; for ( size_t i = 0; i < sizeof( a ); i += sizeof( b ) ) { unsigned long long mask = get_mask( 8 * i, 8 * sizeof( b ) ); b = ( a & mask ) >> 8 * i; std::cout << std::hex << b << std::endl; } return 0; } 

    Output of the program to the console

     12345671fbc00045 45 fbc0 5671 1234 

    In fact, I am the only one who answered your question: :)

    And in general, how to allocate any number of bits from a variable and write them to another?

    You can generalize this function for any integer type by making it template. For example,

     #include <iostream> #include <iomanip> #include <type_traits> template <typename T> T get_mask( size_t pos, size_t n ) { return ~( ~static_cast<typename std::make_unsigned<T>::type>( 0 ) << n ) << pos; } int main() { unsigned long long a = 0x12345671FBC00045; unsigned short b; std::cout << std::hex << a << std::endl; for ( size_t i = 0; i < sizeof( a ); i += sizeof( b ) ) { size_t pos = 8 * i; size_t n = 8 * sizeof( b ); auto mask = get_mask<unsigned long long>( pos, n ); b = ( a & mask ) >> pos; std::cout << "mask = " << std::hex << mask << ", value = " << std::hex << b << std::endl; } return 0; } 

    The output of the program to the console will be

     12345671fbc00045 mask = ffff, value = 45 mask = ffff0000, value = fbc0 mask = ffff00000000, value = 5671 mask = ffff000000000000, value = 1234 

      If the variable b already has the width you require (16 bits in this case), then simply

       b = a >> 32; 

        You can also use struct structures and unions.

         struct _s { unsigned long long one:16; unsigned long long two:16; unsigned long long three:16; unsigned long long four:16; } __attribute__((packed)); union { unsigned long long m; struct _s s; }u; int main(int argc,char * argv[]) { um = 0x12345671FBC00045; printf(" one :> %#x\n",usone); printf(" two :> %#x\n",ustwo); printf(" three :> %#x\n",usthree); printf(" four :> %#x\n",usfour); return 0; } 

        Conclusion :

        one:> 0x45

        two:> 0xfbc0

        three:> 0x5671

        four:> 0x1234

        • uh ... and there is definitely no UB with such a union? - pavel
        • @pavel is unspecified , but not undefined . Because location and packaging of implementation-defined bit bit fields. But if you replace uint16_t , it will not. Another would be to change the tree for the top three :) - 伪位蔚蠂慰位蠀蟿