Reputation: 1974
I'm trying to learn c and am confused why my hex to int conversion function returns a value that is off by one.
Note: 0XAAAA == 46390
#include <stdio.h>
#include <math.h>
unsigned int hex_to_int(char hex[4]);
int main()
{
char hex[4] = "AAAA";
unsigned int result = hex_to_int(hex);
printf("%d 0X%X\n", result, result);
return 0;
}
unsigned int hex_to_int(char input[4])
{
unsigned int sum, i, exponent;
for(i = 0, exponent = 3; i < 4; i++, exponent--) {
unsigned int n = (int)input[i] - 55;
n *= pow(16, exponent);
sum += n;
}
return sum;
}
Output:
46391 0XAAAB
Update: I now realize "- 55" is ridiculous, I was going off memory from seeing this:
if (input[i] >= '0' && input[i] <= '9')
val = input[i] - 48;
else if (input[i] >= 'a' && input[i] <= 'f')
val = input[i] - 87;
else if (input[i] >= 'A' && input[i] <= 'F')
val = input[i] - 55;
Upvotes: 0
Views: 178
Reputation: 213678
You have several bugs such as the string not getting null terminated, and the ASCII to decimal conversion being nonsense (value 55?), you don't initialize sum
and so on. Just do this instead:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char x[] = "AAAA";
unsigned int sum = strtoul(x, NULL, 16);
printf("%d 0X%X\n", sum, sum);
return 0;
}
EDIT
If you insist on doing this manually:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
unsigned int hexstr_to_uint(const char* str);
int main()
{
char x[] = "AAAA";
unsigned int sum = hexstr_to_uint (x);
printf("%d 0X%X\n", sum, sum);
return 0;
}
unsigned int hexstr_to_uint(const char* str)
{
unsigned int sum = 0;
for(; *str != '\0'; str++)
{
sum *= 16;
if(isdigit(*str))
{
sum += *str - '0';
}
else
{
char digit = toupper(*str);
_Static_assert('Z'-'A'==25, "Trash systems not supported.");
if(digit >= 'A' && digit <= 'F')
{
sum += digit - 'A' + 0xA;
}
}
}
return sum;
}
Upvotes: 4
Reputation: 399793
You're just making up logic, there isn't a single value you can subtract from a hexadecimal digit character to convert it into the corresponding number.
If you want to be portable, all that C requires is that the symbols 0
through 9
are consecutive in their encoding. There's no such guarantee for the letters A
through F
.
Also involving pow()
which is a double-precision floating point function in this low-level integer work, is a bit jarring. The typical way to do this is by multiplication or bitwise shifting.
If you're hell-bent on doing the conversion yourself, I usually do something like this:
unsigned int hex2int(const char *a)
{
unsigned int v = 0;
while(isxdigit((unsigned int) *a))
{
v *= 16;
if(isdigit((unsigned int) *a))
v += *a - '0';
else
{
const char highs[] = "abcdef";
const char * const h = strchr(highs, tolower(*a));
v += 10 + (unsigned int) (h - highs);
}
++a;
}
return v;
}
The above is a bit verbose, you can for instance fold the decimal digits into the string used for the letters too, I just tried to be clear. The above should work for any valid C character set encoding, not just ASCII (and it's less passive-aggressive than @Lundin's code, hih :).
Upvotes: 0