Wednesday, February 12, 2014

Bit Manipulation in StackOverflow

I was preparing to get some sleep when I stumped with this question on StackOverflow:"Need to store a string values into a int instead of a 4 byte sized char array". Owhhhh... I totally flipped, sorry the enthusiasm, everybody as addictions, some drink, others smoke, I'm addicted to programming, because when I do it there is something in the code that makes me feel zen!

So the problem is:

1 9 2 . 1 6 8 . 0 0 0 . 0 0 1
How to store this in an int (32 bits)?

Hum, let's see: 2^8 = 0-255 (stores values from 0 to 255)

2^(8 + 8 + 8 + 8) = 2^32 = sizeof(int) = 4 nice!

We can store 4 numbers from 0 to 255 in it, great!

Draft of solution:

int ipaddress = 0; //0x00000000
ipaddress = (192 <<; 32 - 8*1) || (168 << 32 - 8*2) || (0 << 32 - 8*3) || 1; //0x2CBE1AFA01

classA_part = (ipaddress & 0xff000000) >> (32-8*1)
classB_part = ipaddress & 0xff0000
classC_part = ipaddress & 0xff00
classD_part = ipaddress & 0xff

So couple minutes after I read this, I just come with this solution, and it worked like a charm:

#define UPPER32 24
#define UPPER16 16
#define UPPER8  8

int main(void)
{
    int ipaddr = 192 << UPPER32 | 168 << UPPER16 | 0 << UPPER8 | 1; //192 168 000 001
    
    printf("ip address: %d.%d.%d.%d\n",
        (ipaddr & 0xff000000) >> UPPER32,
        (ipaddr & 0xff0000) >> UPPER16,
        (ipaddr & 0xff00) >> UPPER8,
        (ipaddr & 0xff)
    );
    
    return 0;
}

P.S: Yes, couple of minutes, but I'll be humble about this, today I drunk about 2 RedBulls and some coffees, so I'm kind of electric, as you can see... I'm still writing in my blog, while I should be sleeping about an 1 hour ago :) .

Continuing, notice that, the code written as it is, can be strange for some, not everybody wants to deal with bits, so a more elegant approach is possible by simplifying my initial solution, using some macros:

#define UPPER32 24
#define UPPER16 16
#define UPPER8  8

#define IPADDRESS(a,b,c,d)    (a << UPPER32 | b << UPPER16 | c << UPPER8 | d)
#define IPADDRESS_CLASS_A(ip) (((ip & 0xff000000) >> UPPER32) & 0xff)
#define IPADDRESS_CLASS_B(ip) ((ip & 0xff0000) >> UPPER16)
#define IPADDRESS_CLASS_C(ip) ((ip & 0xff00) >> UPPER8)
#define IPADDRESS_CLASS_D(ip) (ipaddr & 0xff)

#define IPADDRESS_FORMAT       "%d.%d.%d.%d"
#define EXTRACT_IPADDR(ip)    
          IPADDRESS_CLASS_A(ip), IPADDRESS_CLASS_B(ip), IPADDRESS_CLASS_C(ip), IPADDRESS_CLASS_D(ip)

int main(void)
{
    int ipaddr = IPADDRESS(192,168,0,1); //192 168 000 001
    printf("ip address: " IPADDRESS_FORMAT "\n", EXTRACT_IPADDR(ipaddr));
    return 0;
}

The clean version looks very much better! 
Note, that the params a,b,c,d in macro IPADDRESS refer to the network classes of the ip address (Class A, B, C, D).

Hope you liked it and stay tuned!