views:

87

answers:

4

How exactly do the following lines work if pData = "abc"?

pDes[1] = ( pData[0] & 0x1c ) >> 2;
pDes[0] = ( pData[0] << 6 ) | ( pData[1] & 0x3f );
+1  A: 

C++ will treat a character as a number according to it's encoding. So, assuming ASCII, 'a' is 97 (which has a bit pattern of 0110_0001) and 'b' is 98 (bit pattern 0110_0010).

Once you think of them as numbers, bit operations on characters should be a bit clearer.

R Samuel Klatchko
+4  A: 

Okay, assuming ASCII which is by no means guaranteed, pData[0] is 'a' (0x61) and pData[1] is 'b' (0x62):

pDes[1]:
    pData[0]               0110 0001
    &0x1c                  0001 1100
                           ---- ----
                           0000 0000
    >>2                    0000 0000  0x00

pDes[0]:
    pData[0]               0110 0001

    << 6           01 1000 0100 0000 (interim value *a)

    pData[1]               0110 0010
    &0x3f                  0011 1111
                   -- ---- ---- ----
                           0010 0010
    |(*a)          01 1000 0100 0000
                   -- ---- ---- ----
                   01 1000 0110 0010  0x1862

How it works:

<< N simply means shift the bits N spaces to the left, >> N is the same but shifting to the right.

The & (and) operation will set each bit of the result to 1 if and only if the corresponding bit in both inputs is 1.

The | (or) operations sets each bit of the result to 1 if one or more of the corresponding bit in both inputs is 1.

Note that the 0x1862 will be truncated to fit into pDes[0] if it's type is not wide enough.

The folowing C program shows this in action:

#include <stdio.h>

int main(void) {
    char *pData = "abc";
    int pDes[2];
    pDes[1] = ( pData[0] & 0x1c ) >> 2;
    pDes[0] = ( pData[0] << 6 ) | ( pData[1] & 0x3f );
    printf ("%08x %08x\n", pDes[0], pDes[1]);
    return 0;
}

It outputs:

00001862 00000000

and, when you change pDes to a char array, you get:

00000062 00000000
paxdiablo
Amarghosh
I found this answer easier to follow than the other one that's a decent answer.
Omnifarious
@Amargosh, yes, I had a rethink about that and you're dead right, the interim is treated as a larger type. Edited to fix.
paxdiablo
@Omnifarious So do I :-)
Amarghosh
Thanks you guies...i really need this :)
rupali
+2  A: 

& is not logical AND - it is bit-wise AND.

a is 0x61, thus pData[0] & 0x1c gives

0x61 0110 0001  
0x1c 0001 1100
--------------
     0000 0000

>> 2 shifts this to right by two positions - value doesn't change as all bits are zero.

pData[0] << 6 left shifts 0x61 by 6 bits to give 01000000 or 0x40

pData[1] & 0x3f

0x62 0110 0010
0x3f 0011 1111
--------------
0x22 0010 0010

Thus it comes down to 0x40 | 0x22 - again | is not logical OR, it is bit-wise.

0x40 0100 0000
0x22 0010 0010
--------------
0x62 0110 0010

The results will be different if pDes is not a char array. Left shifting 0x61 would give you 0001 1000 0100 0000 or 0x1840 - (in case pDes is a char array, the left parts are not in the picture).

0x1840 0001 1000 0100 0000
0x0022 0000 0000 0010 0010
--------------------------
0x1862 0001 1000 0110 0010

pDes[0] would end up as 0x1862 or decimal 6242.

Amarghosh
A: 

In C, all characters are also integers. That means "abc" is equivalent to (char[]){0x61, 0x62, 0x63, 0}.

The & is not the logical AND operator (&&). It is the bitwise AND, which computes the AND at bit-level, e.g.

      'k' = 0x6b ->    0 1 1 0  1 0 1 1
            0x1c ->    0 0 0 1  1 1 0 0   (&
                    ———————————————————
               8 <-    0 0 0 0  1 0 0 0

The main purpose of & 0x1c here is to extract bits #2 ~ #4 from pData[0]. The >> 2 afterwards remove the extra zeros at the end.

Similarly, the & 0x3f is to extract bits #0 ~ #5 from pData[1].

The << 6 pushes 6 zeros at the least significant end of the bits. Assuming pDes[0] is also a char, the most significant 6 bits will be discarded:

     'k' = 0x6b ->                      0 1 1 0 1 0 1 1
                    << 6 = 0 1 1 0 1 0  1 1 0 0 0 0 0 0
                           xxxxxxxxxxx—————————————————
           0xc0 <-                      1 1 0 0 0 0 0 0

In terms of bits, if

                 pData[1]                    pData[0]

pData -> b7 b6 b5 b4 b3 b2 b1 b0     a7 a6 a5 a4 a3 a2 a1 a0

then

pDes  ->  0  0  0  0  0 a4 a3 a2     a1 a0 b5 b4 b3 b2 b1 b0     

                 pDes[1]                     pDes[0]

This looks like an operation to pack three values into a 6-5-5 bit structure.

KennyTM