Type conversion

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


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.
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?
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
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
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;

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