How does C/C++ bit offset work?

Asked

Viewed 23,232 times

14

I would like to understand how the bit offset works in C/C++. I’d also like to understand how the processor performs the calculations and how it handles all this.

I have some examples in C/C++:

void USART_Init(unsigned int ubrr0){
    UBRR0H = (unsigned char)(ubrr0>>8); //Ajusta a taxa de transmissão
    UBRR0L = (unsigned char)ubrr0;

    UCSR0A = 0;
    UCSR0B = (1<<RXEN0)|(1<<TXEN0);     //Habilita a transmissão e a recepção
    UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);   //modo assíncrono, 8 bits de dados, 1 bit de parada, sem paridade
}

I’d also like to understand the difference between << and >>.

Edit

int x = 1; 
x = (x << 8); 

x will be 0001 0000 0000 ?

What happens if I "exceed" the number of bits of a variable? Example:

int x = 1; 
//Representação na memória: 
//{4º byte} {3º byte} {2º byte} {1º byte} 
//0000 0000 0000 0000 0000 0000 0000 0001 
x = (x << 50); //Como ficaria?  

Edit 2:

What operations does the processor do for that value:

int x = 1;          //Corresponde a 0000 0001

Stay this way in memory:

int x1 = (x << 1);  //Corresponde a 0000 0010      

How does it calculate this? Does it store in a temporary "variable" (registrar) and then returns the original position? Do you make any mathematical calculations? (what?) or is it just memory manipulation?

2 answers

8


Bit shift operators "move" all bits of the variable left or right.

C C++ has operators:

>> Right Shift

<< Shift to Left

For example, moving a variable x to the left:

int x = 1; // 0000 0001

int x0 = (x << 0); // 0000 0001 Não deslocado
int x1 = (x << 1); // 0000 0010
int x2 = (x << 2); // 0000 0100
int x3 = (x << 3); // 0000 1000
int x4 = (x << 4); // 0001 0000
int x5 = (x << 5); // 0010 0000
int x6 = (x << 6); // 0100 0000
int x7 = (x << 7); // 1000 0000

Now move to the right:

int x = 128; // 1000 0000

int x0 = (x >> 0); // 1000 0000 Não deslocado
int x1 = (x >> 1); // 0100 0000
int x2 = (x >> 2); // 0010 0000
int x3 = (x >> 3); // 0001 0000
int x4 = (x >> 4); // 0000 1000
int x5 = (x >> 5); // 0000 0100
int x6 = (x >> 6); // 0000 0010
int x7 = (x >> 7); // 0000 0001 

In their example they are possibly used, to configure a serial communication (or something of the type), in which the displacements are used to activate the configuration bits more simply.

For example, if I want to activate some specific bits of a variable UCSR0B, assuming that RXEN0 is 4 and TXEN0 is 3:

(1<<RXEN0) -> (1 << 4) -> (00000001 << 4) -> (00010000)
(1<<TXEN0) -> (1 << 3) -> (00000001 << 3) -> (00001000)

What’s the same as doing:

UCSR0B = 0x10 | 0x8;

That operation (1 << VALOR) is a way of telling the compiler "I want number whose bit number WORTH (to zero base) be 1 and the rest 0".


In case of exceeding the limits of a variable, the result is undefined, as stated in the standard:

(C11, 6.5.7p3) "If the value of the right operand is Negative or is Greater than or Equal to the width of the promoted left operand, the behavior is Undefined"

(C++11, 5.8p1) "The behavior is Undefined if the right operand is Negative, or Greater than or Equal to the length in bits of the promoted left operand."

If you need a limit greater than 32 bits, you can use a variable uint64_t (of stdint.h) to carry out that operation.


To know processor does, the best way is to observe the code assembly generated by the compiler. Which in this case is (generated by Visual Studio 2013):

; int x = 1;
mov DWORD PTR _x$[ebp], 1

; int x1 = (x << 1);
mov eax, DWORD PTR _x$[ebp]
shl eax, 1
mov DWORD PTR _x1$[ebp], eax

In that case, all you want to know is how to instruct shl functions, which displaces the value in eax. Now, the way shl does it depend on the processor.

  • <code>What if I do: int x = 1; x << 8; x will be 0001 0000 0000 ? If int has 32 bits, what happens if I "exceed" this shift limit? Something like: x=1; //Representation in memory: //{4º byte} {3º byte} {2º byte} {1º byte} //0000 0000 0000 0000 0000 0000 0000 0000 0000 0000#Xa; x << 50; How would that look? </code>

  • In this case, you have to assign the result to another variable or to itself x. Type: int b = (x << 8).

  • 1

    Note: right-shift in integers signed is implementation defined. Some compilers use arithmetic shift while others use logical shift. Makes a difference.

  • 1

    If you exceed the limits (or lower 0), I think the result is undefined and may depend on the compiler.

  • @Lucas researched a little more and saw that << >> are multiplications and divisions by 2. Maybe the processor does these operations (multiplication and division) and uses a temporary register to store the values. This information suffices me. Very grateful for the answer and patience. Your reply was excellent.

  • If he crosses the line, he shouldn’t stay 0000 0000 0000 0000 0000 0000 0000 0011, for example?

Show 1 more comment

0

See any C/C++ documentation, for example:
http://www.cplusplus.com/doc/tutorial/operators/
and see the operators defined for the language, its meaning and priority.

<< : deslocamento para a esquerda   
>> : deslocamento para a direita

Note: there are no >>> and <<< operators in C/C++.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.