Hello C -- use of bit operation

Posted by hillbilly928 on Mon, 21 Feb 2022 04:11:22 +0100

ARM is the unified addressing of memory and IO. There are many control registers in SoC. These control registers are set by bit operation of these registers to control peripheral functions. During the process of modifying some bits of the register, other bits cannot be modified.

1, Basis of bit operation

The basic bitwise operators of C language include and, or, XOR, negation, shift left and shift right. As shown in the following table:

Symbol

Description

Operation rules

&      

And

When both bits are 1, the result is 1

|  

Or

When both bits are 0, the result is 0

^    

XOR

The same two bits are 0 and the difference is 1

~   

Reverse

0 to 1, 1 to 0

<< 

Shift left

All binary bits are shifted to the left by several bits, the high bit is discarded, and the low bit is filled with 0

>> 

Shift right

All binary bits are shifted to the right by several bits. For unsigned numbers, high-order complement 0 and signed numbers, the processing methods of each compiler are different. Some complement symbolic bits (arithmetic shift to the right) and some complement 0 (logical shift to the right)

Instructions for bit operation:

1. The six bit operations can only be used for integer data. If you perform bit operations on float and double types, the compiler will report an error.

2. The difference between logical operation and bit operation: logical operation is the logical operation of the overall results of the two expressions involved in the operation, while bit operation is the logical operation of the two data involved in the operation bit by bit according to the corresponding binary number. Logical operators include logical and &, logical or |, logical non!, There are six kinds of operators for bit operation, including bit and &, bit or |, bit XOR ^, bit inversion ~, bit shift left < < and bit shift right > >.

3. If the left shift is > = type len gt h, the gcc compiler will give a warning in GCC environment, but the actual left shift is% of the left shift (8 * sizeof(int)). For example:

int i = 1, j = 0x80000000; //Set int to 32 bits
i = i << 33;   // 33% 32 = 1 shifts 1 bit left, i becomes 2
j = j << 33;   // 33% 32 = 1 shifts 1 bit left, j becomes 0, and the highest bit is discarded

4. In C language, left shift is logic / arithmetic left shift (the two are exactly the same), and right shift is arithmetic right shift, which will keep the sign bit unchanged. Shift left always shifts and zeros. When shifting to the right, the unsigned number is shifted and filled with zero, which is called logical shift to the right; In most cases, the signed number shifts and complements the leftmost bit (that is, complements the most significant bit), and several bits are complemented by several bits. At this time, it is called arithmetic right shift. Arithmetic shift is relative to logical shift. They are the same in the left shift operation. The low bit can be supplemented by 0, but in the right shift, the high bit of logical shift is supplemented by 0, and the high bit of arithmetic shift is supplemented by sign bit.

Shift right handles the sign bit differently from shift left. For signed integers, such as int type, shift right will keep the sign bit unchanged. After the sign bit moves to the right, the positive number is supplemented by 0 and the negative number is supplemented by 1, that is, the arithmetic in assembly language moves to the right. When the number of bits moved exceeds the length of the type, the remainder will be taken, and then the remainder will be moved.

int i = 0x80000000;
i = i >> 1;  //The value of i will not become 0x40000000, but 0xc0000000

5. The operation priority of bit operators is relatively low, because brackets are used as much as possible to ensure the operation order, otherwise it is likely to get mysterious results. For example, you want to get 2^i+1 numbers like 1, 3, 5 and 9. Written as int a = 1 < < i + 1; It's wrong. The program will execute i + 1 first, and then move left. It should be written as int a = (1 < < I) + 1.

2, Use of bit operations

1. Operation and bit&

The essence of bit and operation is to logically sum the two data involved in the operation bit by bit according to the corresponding binary number. Typical applications are as follows:

A. Clear specific data segment

Quickly clear the data of a section of data unit

unsigned int a = 0x00FF1278;
a &= 0xFFFF0FFF;//Clear bit12--bit15 bits of a, a=0x00FF0278
//a &= ~(0xF<<12) ;// Clear bit12--bit15 bits of a, a=0x00FF0278

B. Special location of reserved data area

unsigned int a = 0x00FF1278;
a &= (0xF<<12);//Retain bit12--bit15 bits of a, and clear others, a=0x00001000

C. Judging odd and even numbers

As long as it depends on whether the least significant bit is 0 or 1, 0 is an even number and 1 is an odd number. Therefore, if ((A & 1) = = 0) can be used instead of if (a% 2 = = 0) to judge whether a is an even number

2. Bit or operator|

The essence of bit or operation is to perform logical or operation on the two data involved in the operation bit by bit according to the corresponding binary number. Typical applications are as follows:

A. For data location 1

unsigned int a = 0x00FF0278;
a |= 0x0000F000;//For the 12th-15th position 1 of a, a=0x00FFF278
//a |= (0xF<<12);// For the 12th-15th position 1 of a, a=0x00FFF278

3. Bit exclusive or^

The essence of bit exclusive or operation is to perform logical exclusive or operation on the two data involved in the operation bit by bit according to the corresponding binary number. The result of the corresponding bit is true only when the binary numbers of the corresponding bit are mutually exclusive. Typical applications are as follows:

A. Special positioning inversion

Set the finger position of a data, change 1 to 0 and 0 to 1. For example, if the integer number a=321, the operation of flipping its lower eight bit data is a=a^0XFF.

B. Numerical exchange

a=a^b;
b=b^a;
a=a^b;

Without using third-party variables, you can use bit operation to exchange two numbers

4. Bit non~

The essence of bit non operation is to perform logical non operation on the two data involved in the operation bit by bit according to the corresponding binary number.

A. Transform symbol

The transformation symbol only needs to take the inverse and add 1

5. Bit shift left<<

The essence of shift left operation is to shift the binary value of the corresponding data bit by bit to the left, fill in 0 in the empty position, and overflow and discard the highest bit.

6. Shift bit right > >

The essence of bit right shift operation is to shift the binary value of the corresponding data bit by bit to the right by several bits, and discard the numbers out of bounds. If the current number is an unsigned number, the high order is filled with zero.

If the current data is a signed number, when moving to the right, it is determined whether to fill 0 or 1 on the left according to the sign bit. If the sign bit is 0, fill 0 on the left; However, if the symbol bit is 1, there may be different processing methods according to different computer systems. It can be seen that the bit shift right operation can realize the integer division of divisor 2.

It is suggested that {converting all the division operations of 2 into displacement operations can improve the operation efficiency of the program.

A. Find the absolute value

int i = a >> 31;  
return i == 0 ? a : (~a + 1);  

or

int i = a >> 31;  
return ((a ^ i) - i); 

7. Bit operations commonly used in embedded development

A. Set the register finger position (nth bit) to 1

GPXX |= (1<<n) ;
GPXX |= (1<< 7) | (1<< 4 ) | (1<< 0);//Positions 0, 4 and 7: 1, others reserved

B. Set the register finger position (nth bit) to 0

GPXX &= ~(1<<n );

Clear the nth bit of the register to 0 without affecting the existing state of other bits.

GPXX &= ~(1<<4 );

C. Embedded development bit operation example

    unsigned int i = 0x00ff1234;
    //i |= (0x1<<13);// Bit13 set 1
    //i |= (0xF<<4);// Bit4-bit7 set to 1
    //i &= ~(1<<17);// Clear bit17
    //i &= ~(0x1f<<12);// Clear 5 bits from bit12

    //Take out bit3-bit8
    //i &= (0x3F<<3);// Keep bit3-bit8 and clear other bits
    //i >>= 3;// Shift right 3 bits

    //Assign 937 to bit7-bit17 of the register
    //i &= ~(0x7FF<<7);// Bit7-bit17 reset
    //i |= (937<<7);// Bit7-bit17 assignment

    //Add 17 to the value of registers bit7-bit17
   // unsigned int a = i;// Take a as a copy of I to avoid other bits of I being modified
   // a &= (0x7FF<<7);// Take out bit7-bit17
   //a >>= 7;//
   // a += 17;// Plus 17
   // i &= ~(0x7FF<<7);// Clear bit7-bit17 of I
   // i |= (a<<7);// Write the number after + 17 to bit7-bit17, and other bits remain unchanged

    //Assign 937 to bit7-bit17 of a register and 17 to bit21-bit25
    i &= ~((0x7FF<<7) | (0x1F<<21));//bit7-bit17, bit21-bit25 reset
    i |= ((937<<7) | (17<<21));//bit7-bit17, bit21-bit25 assignment

3, Macro definition of bit operation

//Set the nth bit of 32-bit x (bit0 is the first bit) with macro definition
#define SET_BIT_N(x,n) (x | (1U<<(n-1)))

//Clear the nth bit of 32-bit x (bit0 is the first bit) with macro definition
#define CLEAR_BIT_N(x,n) (x & (~(1U<<(n-1))))

//Set the nth to m bits (bit0 is the first bit) of 32-bit x with macro definition
#define SET_BITS_N_M(x,n,m) (x | (((~0U)>>(32-(m-n+1)))<<(n-1)))

//Clear the nth to m bits (bit0 is the first bit) of 32-bit x with macro definition
#define CLEAR_BITS_N_M(x,n,m) (x & (~(((~0U)>>(32-(m-n+1)))<<(n-1))))

//Use the macro definition to obtain the part from the nth bit to the m bit (bit0 is the first bit) of 32-bit x
#define GET_BITS_N_M(x,n,m) ((x & ~(~(0U)<<(m-n+1))<<(n-1))>>(n-1))

Topics: C C++