Hi, try to explain with my rude english :(
My code (assume that all inputs are corrects. Avoid defensive programing)
#include <stdio.h>
enum { SZ = 11 };
unsigned int htoi(const char *s);
int main()
{
char buff[SZ]; //Max 11 char: 0x XX XX XX XX '\0' (2 + 8 + 1)
while(fscanf(stdin, "%s", buff) != EOF)
printf("%X\n", htoi(buff) );
return 0;
}
unsigned int htoi(const char *s)
{
unsigned int i, r = 0;
for(i = (s[1] == 'x') ? 2 : 0; s[i] != '\0'; i++)
r = ( r << 4 ) + ( (s[i] > '9') ? 0x9 : 0x0 ) + ( s[i] & 0xF );
return r;
}
Ok, first of all, assign r = 0.
Then, when we start for-bucle, we give an init value to index variable i. We have to check if string has 0x format or not. We only need to check position 1 to know if we are treating an input string with 0x format or without it.
Now, we have an index pointing to first correct character! For each iteraion we displace 4 bits to the left. We gain 4 zeros. A perfect gap to add a new hex digit! Example:
Input: 0xBE1234
Is s[1] == 'x' ? true then i = 2;
r = 0;
iter 1: r = 0x0; r = 0x0; r = 0xB;
iter 2: r = 0xB; r = 0xB0; r = 0xBE;
iter 3: r = 0xBE; r = 0xBE0; r = 0xBE1;
iter 4: r = 0xBE1; r = 0xBE10; r = 0xBE12;
iter 5: r = 0xBE12; r = 0xBE120; r = 0xBE123;
iter 6: r = 0xBE123; r = 0xBE1230; r = 0xBE1234
May be this is a bit complicate:
r = ( r << 4 ) + ( (s[i] > '9') ? 0x9 : 0x0 ) + ( s[i] & 0xF );
First of all, we displace 4 bits, same as multiplication per 16 but more efficient. Then, we look if we have an ASCII character bigger than '9'. If it's true, we are working with A, B, C, D, E, F or a, b, c, d, e, f. Remember, we assume that we have a correct input.
Ok, now take a look to ASCII table:
A = 0100 0001 - a = 0110 0001
...
F = 0100 0110 - f = 0110 0110
but we want something like this:
A = 0000 1010 - a = 0000 1010
...
F = 0000 1111 - f = 0000 1111
How we do it? After displacement, we clear 4 most significant bit with mask s[i] & 0xF:
s[2] == 'B' == 0100 0010
s[2] & 0xF == 0000 0010
and add 9 for adapt to an integer value ( only in case that s[i] in { 'A'...'F', 'a' ... 'f' } )
s[2] & 0xF + 0x9 = 0000 0010 + 0000 1001 = 0000 1011 (0xB)
Finally, we add to displaced r value and assign to r. Execution sequence for second iteration (s[3]):
r == 0xB, s[3] == 'E' == 0100 0101 (start iter 2)
(r << 4) == 0xB0, s[3] == 'E' == 0100 0101 (displacement r << 4 )
(r << 4) == 0xB0, (s[3] & 0xF + 0x9) == 0000 1110 == 0xE (clear most significant bits of s[3] and add 0x9)
r = (r << 4) + ( s[3] & 0xF + 0x9 ) == 0xBE == 1011 1110 (add all and assign to r)
What's happen if we have a number character like s[4]?
s[4] == '1' == 0011 0001
s[4] & 0xF == 0000 0001
Displacement r four positions, add 0 (nothing), add result of logic operation s[i] & 0xF and finally, assign to r.
r == 0xBE, s[4] == '1' == 0011 0001 (start iter 3)
(r << 4) == 0xBE0, s[4] == '1' == 0011 0001 (displacement r << 4 )
(r << 4) == 0xBE0, (s[4] & 0xF + 0x0) == 0000 0001 (clear most significant bits of s[4] and add 0)
r = (r << 4) + s[4] & 0xF == 0xBE1 == 1011 1110 0001 (add all and assign)
Remember, we shift 4 so we don't mesh digit bits because we are adding less significant bits with a gap of four zeros.
PD: I promise improve my english for explain better, sorry.