How does bit shift work in C / C ++?

14

I'd like to understand how bit shifting works in C / C ++ . I would also like to understand how the processor performs the calculations and how it handles all of 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 would 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 to make the value:

int x = 1;          //Corresponde a 0000 0001

Stay this way in memory:

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

How does he figure it out? Does it store in a temporary "variable" (register) and then return the original position? Do you do any mathematical calculations? (what?) or is it just memory manipulation?

    
asked by anonymous 22.03.2014 / 15:08

2 answers

8

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

C \ C ++ has the operators:

  

> > Right Shift

     

<

For example, if you move 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 your example they are possibly used to configure a serial (or something like) communication, in which the offsets are used to enable the configuration bits more simply.

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

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

What is the same thing to do:

UCSR0B = 0x10 | 0x8;

This (1 << VALOR) operation is a way of telling the compiler "I want number whose bit number VALUE (for base zero) is 1 and the rest 0".

In case you exceed the limits of a variable, the result is undefined, as it says in the pattern:

  

(C11, 6.5.7p3) "If the value of the right operand is negative   greater than or equal to the width of the left left operand, the   behavior is undefined "

     

(C ++ 11, 5.8p1) "The behavior is undefined if the 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 uint64_t ( stdint.h ) variable to perform this operation.

To know how processor does, the best way is to observe the assembly code generated by the compiler. Which in the case is this (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 this case, all you want to know is how the shl statement works, which shifts the value to eax . Now, how shl does this will depend on the processor.

    
22.03.2014 / 15:47
0

See any C / C ++ documentation, such as:
link
and see the operators defined for the language, its meaning and priority.

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

Note: there are no operators > > > e

22.03.2014 / 15:19