简体   繁体   中英

Why is my hex conversion function off by one?

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;

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;
}

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 :).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM