Type conversion

May 19, 2015 at 9:53am
Hello,

I need to convert a string of hexadecimal digits into it`s equivalent integer value but getting these results:

0X3F. 0

0XFFFF. 0

0X0000000UL. 0


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66

#include <iostream>
#include <stdlib.h>

unsigned int htoi ( char s[] );


int main (void)

{

  char * test [ ] =

  {
    "0X3F",
    "0XFFFF",
    "0X0000000UL"
    
  };

 unsigned int result;
 char * end = NULL;
 
 size_t N =  sizeof(test) / sizeof test[0];
 
 for (int i = 0; i < N; ++i)
 
 {
   result = htoi( test[i]) ;
   long j = strtol( test[N], &end, 16);
   
   if ( end != NULL && result == j)
   
   printf( " %s. %d\n" , test[i], result );
   
    else
    {
      printf(" %s. Incorrect. %d\n", test[i], result);
    
    }
  
  }

}




unsigned int htoi ( char s[] )
{

   int i = 0;
   char c;
   unsigned int answer = 0;

 if ( c == '0' && (s[i] == 'x' || s[i] == 'X') &&
 	            ((s[i] >= '0' && s[i] <= '9') ||
 	            (s[i] >= 'A' && s[i] <= 'F') || 	    
                   (s[i] >= 'a' && s[i] <= 'f'))) 

       c = s[i];
       answer = 16 * answer + ( s[i] - '0');
       return answer;

}



Any help is appreciated, thanks
May 19, 2015 at 12:33pm
First of all, you could get an help from C++ Shell: you will receive 4 warnings.
Try to fix those warnings and then use a debugger to see what your code is doing.
It it is not a mere exercise, you could use the class std::istringstream.
May 19, 2015 at 12:52pm
Hi,

I think class is a C++ object, there is no such thing as 'class' in plain C.

However when I try to compile this at least I get this error:

main.cpp:29:27: warning: array subscript is above array bounds [-Warray-bounds]

long j = strtol( test[N], &end, 16);


I have no idea where it came from.
May 19, 2015 at 2:55pm
Well, N is the size of the array. As an index it is of course out of bounds. What are you trying to do with this line?
Last edited on May 19, 2015 at 2:55pm
May 19, 2015 at 4:31pm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <string.h>

const char* skip_prefix( const char* hexstr )
{
    if(hexstr)
    {
        while( isspace(*hexstr) ) ++hexstr ; // skip leading whitespace

        char c = *hexstr ;

        if( c == 0 ) return NULL ;
        else if( c == '0' )
        {
           c = *++hexstr ; // skip leading zero
           if( c == 'x' || c == 'X' ) ++hexstr ; // skip leading 0x 0X
        }
    }

    return hexstr ;
}

int value( char digit )
{
    if( digit >= '0' && digit <= '9' ) return digit - '0' ;

    digit = tolower(digit) ;
    switch(digit)
    {
        case 'a' : return 10 ;
        case 'b' : return 11 ;
        case 'c' : return 12 ;
        case 'd' : return 13 ;
        case 'e' : return 14 ;
        case 'f' : return 15 ;
    }
    return -1 ;
}

unsigned int hexstr_to_uint( const char* hexstr )
{
    hexstr = skip_prefix(hexstr) ;
    if( !hexstr ) { errno = EINVAL ; return 0 ; } // null pointer

    // static assertion: long_long_is_bigger_than_int
    enum { assume_long_long_is_bigger_than_int = 1 / ( sizeof(long long) - sizeof(int) ) } ;
    unsigned long long number = 0 ;

    int digit_value = 0 ;

    for( ; ( digit_value = value(*hexstr) ) != -1 ; ++hexstr )
    {
        number *= 16 ;
        number += digit_value ;
        if( number > UINT_MAX ) { errno = ERANGE ; return 0 ; } // out of the range of unsigned int
    }

    if( *hexstr != 0 ) { errno = EINVAL ; return 0 ; } // not fully parsed

    return number ;
    
    // TODO:
    // 1. support optional integer-literal-suffix 
    // 2. allow optional unary + or - operators (leading sign)
}

int main()
{
    const char* const test[] = { "ffff", "0x0001", "0X0082345678", "0129", "129x", "0x100000000", NULL, "00001" } ;
    enum { N = sizeof(test) / sizeof(*test) };

    for( int i = 0 ; i < N ; ++i )
    {
        errno = 0 ;
        unsigned int value =  hexstr_to_uint( test[i] ) ;
        printf( "\nstr: '%s' => uint: %u 0x%x   status: %s\n",
                ( test[i] ? test[i] : "NULL" ), value, value, strerror(errno) ) ;
    }
}

http://coliru.stacked-crooked.com/a/e9cd5e1fe9569523
May 19, 2015 at 5:01pm
Well, N is the size of the array. As an index it is of course out of bounds. What are you trying to do with this line?


Why can`t I compare size_t with int?
May 19, 2015 at 5:22pm
Why can`t I compare size_t with int?


Who said you couldn't? Your question doesn't relate to the text you quoted in any way.

If you define an array to have N elements, then the first element has index 0, and the last has index (N-1). If you try and use N as the index, you have gone past the end of your array.
May 19, 2015 at 6:43pm
I think I`m pretty close to a working program here:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105

#include <iostream>
#include <stdlib.h>

unsigned int htoi ( char s[] );
int alpha_to_int ( int x );


int main (void)

{

  char * test [ ] =

  {
    "0X3F",
    "0XFFFF",
    "0X0000000UL"
    
  };

 unsigned int result;
 char * end = NULL;
 
 size_t N =  sizeof(test) / sizeof test[0];
 
 for (int i = 0; i < N-1; ++i)
 
 {
   result = htoi( test[i]) ;
   long j = strtol( test[N-1], &end, 16);
   
   if ( end != NULL && result == j)
   
   printf( " %s. %d\n" , test[i], result );
   
    else
    {
      printf(" %s. Incorrect. %d\n", test[i], result);
    
    }
  
  }

}




unsigned int htoi ( char s[], )
{

   int i = 0;
   int valid;
   int hexit;
   char c;
   unsigned int answer = 0;

 if ( c == '0' && (s[i] == 'x' || s[i] == 'X') &&
 	            ((s[i] >= '0' && s[i] <= '9') ||
 	            (s[i] >= 'A' && s[i] <= 'F') || 	    
                   (s[i] >= 'a' && s[i] <= 'f'))) 

     {
       c = s[i];
       valid = 1;
     )
     
     while(valid && s[i] != 0)
  {
       answer = 16 * answer + ( s[i] - '0');
       return answer;

  }
  
  else
  
     hexit = alpha_to_int(s[i])
     
}
     
  
 int alpha_to_int( int x)
{
  
  char c;
  int i;
  
  for ( ; c = s[i]++) {
    
  if (c >= 'A' && c <= 'Z')
    c -= 'A' - 10;
    
  else if (c >= 'a' && c <= 'z')
    c -= 'a' - 10;
   
  else 
        break; 
    
  }
  
}


May 20, 2015 at 8:49am
There are a lot of compiler errors (like line 50: ( char s[], ) or line 76: misplaced else). Please correct them or ask if you have a problem.
May 20, 2015 at 9:25am
Also, the for loop on line 89 makes no sense. Perhaps you need to go back to your textbook and remind yourself how to do a for loop?
May 20, 2015 at 3:40pm
I do want to make this work but I don`t want to replace my whole code like JLBorges did.

here is my code so far, any suggestions or corrections are welcome:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107

#include <iostream>
#include <stdlib.h>

unsigned int htoi ( char s[] );
int alpha_to_int ( int x );


int main (void)

{

  char * test [ ] =

  {
    "0X3F",
    "0XFFFF",
    "0X0000000UL"
    
  };

 unsigned int result;
 char * end = NULL;
 
 size_t N =  sizeof(test) / sizeof test[0];
 
 for (int i = 0; i < N-1; ++i)
 
 {
   result = htoi( test[i]) ;
   long j = strtol( test[N-1], &end, 16);
   
   if ( end != NULL && result == j)
   
   printf( " %s. %d\n" , test[i], result );
   
    else
    {
      printf(" %s. Incorrect. %d\n", test[i], result);
    
    }
  
  }

}




unsigned int htoi ( char * hexstring )
{

   int i = 0;
   int hexit;
   unsigned int answer = 0;

 
      while( *hexstring != 0)
     
  {
    
     if(*hexstring >= '0' && *hexstring <= '9')
     
     {
       answer = 16 * answer + ( *hexstring - '0');
       return answer;
       
     }

  
    else
  
    {
      hexit = alpha_to_int(*hexstring)
    }
    
     
      ++hexstring;
     
 }
     
  
 int alpha_to_int( char *)
{
  
  const char * s;
  char c;
  int i;
  
  for ( ; ; c = *s++) {
    
  if (c >= 'A' && c <= 'Z')
    c -= 'A' - 10;
    return c;
    
  else if (c >= 'a' && c <= 'z')
    c -= 'a' - 10;
    return c;
   
  else 
        break; 
    
  }
  
}

Last edited on May 20, 2015 at 3:46pm
May 20, 2015 at 5:55pm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>

unsigned int ctoi(char c) // turn hex digit into integer value
{
   if(c >= '0' && c <= '9') // numeric digit
      return (c - '0');
   if(c >= 'a' && c <= 'f') // lower-case alpha digit
      return (c - 'a') + 10;
   if(c >= 'A' && c <= 'F') // upper-case alpha digit
      return (c - 'A') + 10;
   return 0; // ignore everything else
}

unsigned int htoi(char *s) // turn hex string into integer value
{
   unsigned int idx = 0, m = 0, i = 0;
   while(s[idx+1] != 0) idx++; // go to right-most character
   while(idx) // process till we hit left-most character
   {
      if(!m) // right-most digit
      {
         m = 16; // next base multiplier
         i += ctoi(s[idx]); // get integer digit value
      } else {
         i += (m * ctoi(s[idx])); // integer digit value times base multiplier
         m *= 16; // next base multiplier
      }
      idx--; // move index left
   }
   return i;
}

int main()
{
  char *test1 = "0xFF";
  char *test2 = "0x00FF";
  char *test3 = "0xFF00FF";
  std::cout << " Test 1 (" << test1 << ") = " << htoi(test1) << std::endl;
  std::cout << " Test 2 (" << test2 << ") = " << htoi(test2) << std::endl;
  std::cout << " Test 3 (" << test3 << ") = " << htoi(test3) << std::endl;
  return 0;
}



 Test 1 (0xFF) = 255
 Test 2 (0x00FF) = 255
 Test 3 (0xFF00FF) = 16711935
May 20, 2015 at 8:22pm
Or even better:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

#include <stdio.h>

unsigned int ctoi(char c) // turn hex digit into integer value
{
   if(c >= '0' && c <= '9') // numeric digit
      return (c - '0');
   if(c >= 'a' && c <= 'f') // lower-case alpha digit
      return (c - 'a') + 10;
   if(c >= 'A' && c <= 'F') // upper-case alpha digit
      return (c - 'A') + 10;
   return 0; // ignore everything else
}

unsigned int htoi(char *s) // turn hex string into integer value
{
   unsigned int idx = 0, m = 0, i = 0;
   while(s[idx+1] != 0) idx++; // go to right-most character
   while(idx) // process till we hit left-most character
   {
      if(!m) // right-most digit
      {
         m = 16; // next base multiplier
         i += ctoi(s[idx]); // get integer digit value
      } else {
         i += (m * ctoi(s[idx])); // integer digit value times base multiplier
         m *= 16; // next base multiplier
      }
      idx--; // move index left
   }
   return i;
}

int main()
{
  const char * test [ ] =  { "OX3F", "OX00000UL", "abcd" }
  size_t thistest =  sizeof(test) / sizeof(*test);
  
  for (int i = 0; i < thistest; ++i)
  
  {
     
  unsigned int value =  htoi( test[i] ) ;
  printf( " %s, %u, test[i], value " );
 
  return 0;

 }
}
May 21, 2015 at 12:48am
I actually wrote a function for this that mathematically converts strings to ints using a formula I painstakingly derived. If you convert the hex to base-10, it shouldn't be too difficult to convert each digit to it's integer equivilant.
Topic archived. No new replies allowed.