Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

bitwise shifts, unsigned chars

Tags:

c++

c

bitwise-and

Can anyone explain verbosely what this accomplishes? Im trying to learn c and am having a hard time wrapping my head around it.

void tonet_short(uint8_t *p, unsigned short s) {
  p[0] = (s >> 8) & 0xff;
  p[1] = s & 0xff;
}

void tonet_long(uint8_t *p, unsigned long l)
{
  p[0] = (l >> 24) & 0xff;
  p[1] = (l >> 16) & 0xff;
  p[2] = (l >> 8) & 0xff;
  p[3] = l & 0xff;
}
like image 632
mylegfeelsfunny Avatar asked Dec 13 '25 11:12

mylegfeelsfunny


2 Answers

Verbosely, here it goes:

As a direct answer; both of them stores the bytes of a variable inside an array of bytes, from left to right. tonet_short does that for unsigned short variables, which consist of 2 bytes; and tonet_long does it for unsigned long variables, which consist of 4 bytes.

I will explain it for tonet_long, and tonet_short will just be the variation of it that you'll hopefully be able to derive yourself:

unsigned variables, when their bits are bitwise-shifted, get their bits shifted towards the determined side for determined amount of bits, and the vacated bits are made to be 0, zeros. I.e.:

unsigned char asd = 10; //which is 0000 1010 in basis 2
asd <<= 2;              //shifts the bits of asd 2 times towards left
asd;                    //it is now 0010 1000 which is 40 in basis 10

Keep in mind that this is for unsigned variables, and these may be incorrect for signed variables.

The bitwise-and & operator compares the bits of two operands on both sides, returns a 1 (true) if both are 1 (true), and 0 (false) if any or both of them are 0 (false); and it does this for each bit. Example:

unsigned char asd = 10; //0000 1010
unsigned char qwe = 6;  //0000 0110
asd & qwe;              //0000 0010 <-- this is what it evaluates to, which is 2

Now that we know the bitwise-shift and bitwise-and, let's get to the first line of the function tonet_long:

p[0] = (l >> 24) & 0xff;

Here, since l is unsigned long, the (l >> 24) will be evaluated into the first 4 * 8 - 24 = 8 bits of the variable l, which is the first byte of the l. I can visualize the process like this:

abcd efgh   ijkl mnop   qrst uvwx   yz.. ....   //letters and dots stand for
                                                //unknown zeros and ones
//shift this 24 times towards right
0000 0000   0000 0000   0000 0000   abcd efgh

Note that we do not change the l, this is just the evaluation of l >> 24, which is temporary.

Then the 0xff which is just 0000 0000 0000 0000 0000 0000 1111 1111 in hexadecimal (base 16), gets bitwise-anded with the bitwise-shifted l. It goes like this:

0000 0000   0000 0000   0000 0000   abcd efgh
&
0000 0000   0000 0000   0000 0000   1111 1111
=
0000 0000   0000 0000   0000 0000   abcd efgh

Since a & 1 will be simply dependent strictly on a, so it will be a; and same for the rest... It looks like a redundant operation for this, and it really is. It will, however, be important for the rest. This is because, for example, when you evaluate l >> 16, it looks like this:

0000 0000   0000 0000   abcd efgh   ijkl mnop

Since we want only the ijkl mnop part, we have to discard the abcd efgh, and that will be done with the aid of 0000 0000 that 0xff has on its corresponding bits.

I hope this helps, the rest happens like it does this far, so... yeah.

like image 185
Utkan Gezer Avatar answered Dec 15 '25 06:12

Utkan Gezer


These routines convert 16 and 32 bit values from native byte order to standard network(big-endian) byte order. They work by shifting and masking 8-bit chunks from the native value and storing them in order into a byte array.

like image 42
Chris Dodd Avatar answered Dec 15 '25 06:12

Chris Dodd



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!