3

I have hexadecimal values stored as characters:

char A = '0';
char B = '6';
char C = 'E';

... I need them coverted to integers. I know 'atoi', but this only works for decimal coded char values. Any similar function?

1
  • Apart from atoi what have you tried? Commented Aug 16, 2012 at 12:16

7 Answers 7

7
int v = (A > '9')? (A &~ 0x20) - 'A' + 10: (A - '0');

is correct for ASCII. For other character sets, a similar approach would work, but you would then want toupper instead of &~ 0x20.

Sign up to request clarification or add additional context in comments.

7 Comments

I need new value as integer, not char.
@jurij: char is an integral type, plenty big enough to hold 0-15, but I changed it to make you happy.
@junj, replace char v with int v. You do know that char is just the shortest signed integer type, right?
Yes, but I need new values as int to do some math with them later.
This is very encoding dependent. It supposes, for example, that the codes for 'A'-'F' and 'a'-'f' are larger (numerically) than the codes for '0'-'9'. Which is true for ASCII, but not necessarily for other encodings. (It's not true for EBCDIC, for example.)
|
4

You could try strtol. But strtol needs a 0 terminated char *, so:

long x = strtol((char[]){A, 0}, NULL, 16);

2 Comments

But please note, (char[]){} requires a recent compiler version with support for C++11 initialization syntax.
@BenVoigt Actually we've had it since C99.
3

In C:

const char chrs[] = "0123456789ABCDEF";

int value = -1; // sentinel
const char *loc = strchr(chrs, ch);
if (loc)
    value = loc - chrs;

or, using C++:

const std::string chrs("0123456789ABCDEF");
int value = chrs.find(ch);

Comments

1

You can explicity state you want to use base 16 with strtol

char C = 'E';
int num = strtol (&C ,NULL,16); // 14

Beware that C is not a null terminated array, simply solved if you can change your characters to the following:

char C[] = "E";
int num = strtol(C, NULL, 16);

4 Comments

&C is not a null-terminated array!
Should work on little endian systems if C is short, int, long or any other integer type with larger size than char :) (also the pointer should be casted to char * then)
It's undefined behavior, which is more than just living on the edge. It may work most of the time, but give a wrong value from time to time. Or even crash (although I'll admit that I find that highly unlikely).
Granted, but this illustration was targeted at the use of strtol and it's optional base capabilities. I'll make some amendments.
0

The obvious solution is to make a one character string, and use the standard conversion techniques on it:

std::istringstream tmp( std::string( 1, A ) );
tmp >> anInt;

It's a bit heavy, however (to put it lightly), and probably not very efficient in terms of runtime (a litote if I ever heard one).

One simple and robust solution is a table lookup:

static char const digits[] = "0123456789ABCDEF";
int value = std::find(digits, digits + 16, A) - digits;
if (value >= 16) {
    //  A wasn't a hex digit...
}

Alternatively (and much faster) is to use the character as an index into a table:

static signed char const values[] =
{
    -1, -1, -1, -1, -1, -1, -1, -1,     //  0x00-0x07
    //  ...
     0,  1,  2,  3,  4,  5,  6,  7,     //  0x30-0x37
     8,  9, -1, -1, -1, -1, -1, -1,     //  0x38-0x3F
    -1, 10, 11, 12, 13, 14, 15, -1,     //  0x40-0x47
    //  ...
    -1, 10, 11, 12, 13, 14, 15, -1,     //  0x60-0x67
    //  ...
};


int value = values[static_cast<unsigned char>( A )];

Note that this is very dependent on the encoding; you might want to build it up at runtime from a list of digits, to avoid any encoding issues. Something like:

struct ValueTable
{
    signed char values[256];
    ValueTable()
    {
        std::fill( begin(values), end(values), -1 );
        static char const digits[] = "0123456789ABCDEF";
        for ( int i = 0; i < 16; ++ i ) {
            values[ digits[i] = i;
            values[ tolower( digits[i] ) ] = i;
        }
    }
};
static ValueTable const map;

//   ...
int value = map.values[ static_cast<unsigned char>( A ) ];

Comments

0
#include <stdio.h>
#include <stdlib.h>


int xtoi(char c)
{
    int v = -1;
    char w=toupper(c);
    if(w >= 'A' && w <= 'F'){
        v = w - 'A' + 0x0A;
    }else if (w >= '0' && w <= '9'){
        v = w - '0';
    }

    return v;
}

int main(int argc,char **argv)
{
    printf("v:%p\n",argc == 2 ? xtoi(argv[1][0]):-1);
    return 0;
}

Comments

0

I had a similar problem, but mine involved also verifying that it was a valid Hexidecimal character. Below is my solution that converts from hex char to a binary nibble. (Note: You may want to change uint8_t to int).

The benefit of this approach is that instead of individually checking each character against a lookup table. There is only up to 6 comparison (aside from the null pointer guard) before it can output the answer.

/**-----------------------------------------------------------------------------
  @brief Converts Hexidecimal Char Value Into Binary Nibble Format
  Converts 0-9 & a-f & A-F Hex notation to binary nibble between 0x00 to 0x0F
  Return: True if valid nibble is avaliable at nibble_out else it returns false
------------------------------------------------------------------------------*/
bool char_to_nibble(const char ch, uint8_t *nibble_out)
{ /* Assumes char ch is encoded in ascii */
  if (!nibble_out)
  { /* Output Pointer Cannot Be Null */
    return false;
  }
  if ( '0' <= ch && ch <= '9' )
  { /* Integer Character */
    *nibble_out = ch - '0';
    return true;
  }
  if ( 'a' <= ch && ch <= 'f' )
  { /* Lowercase Letter Character */
    *nibble_out = ch - 'a' + 10;
    return true;
  }
  if ( 'A' <= ch && ch <= 'F' )
  { /* Upper Case Character */
    *nibble_out = ch - 'A' + 10;
    return true;
  }
  return false;
}

The above function is confirmed to be functional. Proof in test program below.

Test Program

This program demonstrates char_to_nibble() and it's usage.

/*******************************************************************************
  Parse Hexidecimal Char to binary Nibble ( In C Language )
  Brian Khuu 2017
*******************************************************************************/
// Tip: tcc -run ${This File}
#include <stdint.h>  // Standard Integer (e.g. uint8_t )
#include <stdbool.h> // Standard Boolean
#include <stdio.h>   // printf()
#include <ctype.h>   // isprint()
#include <stdio.h>   // sscanf()

/**-----------------------------------------------------------------------------
  @brief Converts Hexidecimal Char Value Into Binary Nibble Format
  Converts 0-9 & a-f & A-F Hex notation to binary nibble between 0x00 to 0x0F
  Return: True if valid nibble is avaliable at nibble_out else it returns false
------------------------------------------------------------------------------*/
bool char_to_nibble(const char ch, uint8_t *nibble_out)
{ /* Assumes char ch is encoded in ascii */
  if (!nibble_out)
  { /* Output Pointer Cannot Be Null */
    return false;
  }
  if ( '0' <= ch && ch <= '9' )
  { /* Integer Character */
    *nibble_out = ch - '0';
    return true;
  }
  if ( 'a' <= ch && ch <= 'f' )
  { /* Lowercase Letter Character */
    *nibble_out = ch - 'a' + 10;
    return true;
  }
  if ( 'A' <= ch && ch <= 'F' )
  { /* Upper Case Character */
    *nibble_out = ch - 'A' + 10;
    return true;
  }
  return false;
}

/*******************************************************************************
  Demonstration of char_to_nibble()
*******************************************************************************
  - Running this program without an argument will spit out the full table.
  - Running this program with one char per argument will run a partial test.
*/

void test(const char ch)
{ /* Runs a test on this char and display the result */
  uint8_t nibble = 0;
  /* Function Under Test */
  bool result = char_to_nibble(ch, &nibble);
  /* Print Result */
  printf("| 0x%02X, `%c` | %2u     | %s |\r\n", (uint8_t) ch, (isprint(ch)?ch:' '), nibble, (result?"**TRUE**":" FALSE  ") );
}

#define ARGTOINT(arg, var) if((argc-1) >= arg){sscanf(argv[arg], "%d", &var);}

int main(int argc, char *argv[])
{
  printf("| Input     | Output | Is Hex?  |\r\n");
  printf("|-----------|--------|----------|\r\n");
  if (argc == 1)
  { /* self test on no param */
    for (uint16_t i = 0 ; i < 256 ; i++) test((char)i);
    return 0;
  }
  for (int i = 1 ; i < argc ; i++)
  { /* Process user input (e.g. "a b c d e ..." )*/
    char ch = *(argv[i]);
    test(ch);
  }
  return 0;
}

Full Table Output

This table was generated by running the above test program (empty arg mode). This demonstrates that this function is working as expected.

| Input     | Output | Is Hex?  |
|-----------|--------|----------|
| 0x00, ` ` |  0     |  FALSE   |
| 0x01, ` ` |  0     |  FALSE   |
| 0x02, ` ` |  0     |  FALSE   |
| 0x03, ` ` |  0     |  FALSE   |
| 0x04, ` ` |  0     |  FALSE   |
| 0x05, ` ` |  0     |  FALSE   |
| 0x06, ` ` |  0     |  FALSE   |
| 0x07, ` ` |  0     |  FALSE   |
| 0x08, ` ` |  0     |  FALSE   |
| 0x09, ` ` |  0     |  FALSE   |
| 0x0A, ` ` |  0     |  FALSE   |
| 0x0B, ` ` |  0     |  FALSE   |
| 0x0C, ` ` |  0     |  FALSE   |
| 0x0D, ` ` |  0     |  FALSE   |
| 0x0E, ` ` |  0     |  FALSE   |
| 0x0F, ` ` |  0     |  FALSE   |
| 0x10, ` ` |  0     |  FALSE   |
| 0x11, ` ` |  0     |  FALSE   |
| 0x12, ` ` |  0     |  FALSE   |
| 0x13, ` ` |  0     |  FALSE   |
| 0x14, ` ` |  0     |  FALSE   |
| 0x15, ` ` |  0     |  FALSE   |
| 0x16, ` ` |  0     |  FALSE   |
| 0x17, ` ` |  0     |  FALSE   |
| 0x18, ` ` |  0     |  FALSE   |
| 0x19, ` ` |  0     |  FALSE   |
| 0x1A, ` ` |  0     |  FALSE   |
| 0x1B, ` ` |  0     |  FALSE   |
| 0x1C, ` ` |  0     |  FALSE   |
| 0x1D, ` ` |  0     |  FALSE   |
| 0x1E, ` ` |  0     |  FALSE   |
| 0x1F, ` ` |  0     |  FALSE   |
| 0x20, ` ` |  0     |  FALSE   |
| 0x21, `!` |  0     |  FALSE   |
| 0x22, `"` |  0     |  FALSE   |
| 0x23, `#` |  0     |  FALSE   |
| 0x24, `$` |  0     |  FALSE   |
| 0x25, `%` |  0     |  FALSE   |
| 0x26, `&` |  0     |  FALSE   |
| 0x27, `'` |  0     |  FALSE   |
| 0x28, `(` |  0     |  FALSE   |
| 0x29, `)` |  0     |  FALSE   |
| 0x2A, `*` |  0     |  FALSE   |
| 0x2B, `+` |  0     |  FALSE   |
| 0x2C, `,` |  0     |  FALSE   |
| 0x2D, `-` |  0     |  FALSE   |
| 0x2E, `.` |  0     |  FALSE   |
| 0x2F, `/` |  0     |  FALSE   |
| 0x30, `0` |  0     | **TRUE** |
| 0x31, `1` |  1     | **TRUE** |
| 0x32, `2` |  2     | **TRUE** |
| 0x33, `3` |  3     | **TRUE** |
| 0x34, `4` |  4     | **TRUE** |
| 0x35, `5` |  5     | **TRUE** |
| 0x36, `6` |  6     | **TRUE** |
| 0x37, `7` |  7     | **TRUE** |
| 0x38, `8` |  8     | **TRUE** |
| 0x39, `9` |  9     | **TRUE** |
| 0x3A, `:` |  0     |  FALSE   |
| 0x3B, `;` |  0     |  FALSE   |
| 0x3C, `<` |  0     |  FALSE   |
| 0x3D, `=` |  0     |  FALSE   |
| 0x3E, `>` |  0     |  FALSE   |
| 0x3F, `?` |  0     |  FALSE   |
| 0x40, `@` |  0     |  FALSE   |
| 0x41, `A` | 10     | **TRUE** |
| 0x42, `B` | 11     | **TRUE** |
| 0x43, `C` | 12     | **TRUE** |
| 0x44, `D` | 13     | **TRUE** |
| 0x45, `E` | 14     | **TRUE** |
| 0x46, `F` | 15     | **TRUE** |
| 0x47, `G` |  0     |  FALSE   |
| 0x48, `H` |  0     |  FALSE   |
| 0x49, `I` |  0     |  FALSE   |
| 0x4A, `J` |  0     |  FALSE   |
| 0x4B, `K` |  0     |  FALSE   |
| 0x4C, `L` |  0     |  FALSE   |
| 0x4D, `M` |  0     |  FALSE   |
| 0x4E, `N` |  0     |  FALSE   |
| 0x4F, `O` |  0     |  FALSE   |
| 0x50, `P` |  0     |  FALSE   |
| 0x51, `Q` |  0     |  FALSE   |
| 0x52, `R` |  0     |  FALSE   |
| 0x53, `S` |  0     |  FALSE   |
| 0x54, `T` |  0     |  FALSE   |
| 0x55, `U` |  0     |  FALSE   |
| 0x56, `V` |  0     |  FALSE   |
| 0x57, `W` |  0     |  FALSE   |
| 0x58, `X` |  0     |  FALSE   |
| 0x59, `Y` |  0     |  FALSE   |
| 0x5A, `Z` |  0     |  FALSE   |
| 0x5B, `[` |  0     |  FALSE   |
| 0x5C, `\` |  0     |  FALSE   |
| 0x5D, `]` |  0     |  FALSE   |
| 0x5E, `^` |  0     |  FALSE   |
| 0x5F, `_` |  0     |  FALSE   |
| 0x60, ``` |  0     |  FALSE   |
| 0x61, `a` | 10     | **TRUE** |
| 0x62, `b` | 11     | **TRUE** |
| 0x63, `c` | 12     | **TRUE** |
| 0x64, `d` | 13     | **TRUE** |
| 0x65, `e` | 14     | **TRUE** |
| 0x66, `f` | 15     | **TRUE** |
| 0x67, `g` |  0     |  FALSE   |
| 0x68, `h` |  0     |  FALSE   |
| 0x69, `i` |  0     |  FALSE   |
| 0x6A, `j` |  0     |  FALSE   |
| 0x6B, `k` |  0     |  FALSE   |
| 0x6C, `l` |  0     |  FALSE   |
| 0x6D, `m` |  0     |  FALSE   |
| 0x6E, `n` |  0     |  FALSE   |
| 0x6F, `o` |  0     |  FALSE   |
| 0x70, `p` |  0     |  FALSE   |
| 0x71, `q` |  0     |  FALSE   |
| 0x72, `r` |  0     |  FALSE   |
| 0x73, `s` |  0     |  FALSE   |
| 0x74, `t` |  0     |  FALSE   |
| 0x75, `u` |  0     |  FALSE   |
| 0x76, `v` |  0     |  FALSE   |
| 0x77, `w` |  0     |  FALSE   |
| 0x78, `x` |  0     |  FALSE   |
| 0x79, `y` |  0     |  FALSE   |
| 0x7A, `z` |  0     |  FALSE   |
| 0x7B, `{` |  0     |  FALSE   |
| 0x7C, `|` |  0     |  FALSE   |
| 0x7D, `}` |  0     |  FALSE   |
| 0x7E, `~` |  0     |  FALSE   |
| 0x7F, ` ` |  0     |  FALSE   |
| 0x80, ` ` |  0     |  FALSE   |
| 0x81, ` ` |  0     |  FALSE   |
| 0x82, ` ` |  0     |  FALSE   |
| 0x83, ` ` |  0     |  FALSE   |
| 0x84, ` ` |  0     |  FALSE   |
| 0x85, ` ` |  0     |  FALSE   |
| 0x86, ` ` |  0     |  FALSE   |
| 0x87, ` ` |  0     |  FALSE   |
| 0x88, ` ` |  0     |  FALSE   |
| 0x89, ` ` |  0     |  FALSE   |
| 0x8A, ` ` |  0     |  FALSE   |
| 0x8B, ` ` |  0     |  FALSE   |
| 0x8C, ` ` |  0     |  FALSE   |
| 0x8D, ` ` |  0     |  FALSE   |
| 0x8E, ` ` |  0     |  FALSE   |
| 0x8F, ` ` |  0     |  FALSE   |
| 0x90, ` ` |  0     |  FALSE   |
| 0x91, ` ` |  0     |  FALSE   |
| 0x92, ` ` |  0     |  FALSE   |
| 0x93, ` ` |  0     |  FALSE   |
| 0x94, ` ` |  0     |  FALSE   |
| 0x95, ` ` |  0     |  FALSE   |
| 0x96, ` ` |  0     |  FALSE   |
| 0x97, ` ` |  0     |  FALSE   |
| 0x98, ` ` |  0     |  FALSE   |
| 0x99, ` ` |  0     |  FALSE   |
| 0x9A, ` ` |  0     |  FALSE   |
| 0x9B, ` ` |  0     |  FALSE   |
| 0x9C, ` ` |  0     |  FALSE   |
| 0x9D, ` ` |  0     |  FALSE   |
| 0x9E, ` ` |  0     |  FALSE   |
| 0x9F, ` ` |  0     |  FALSE   |
| 0xA0, ` ` |  0     |  FALSE   |
| 0xA1, ` ` |  0     |  FALSE   |
| 0xA2, ` ` |  0     |  FALSE   |
| 0xA3, ` ` |  0     |  FALSE   |
| 0xA4, ` ` |  0     |  FALSE   |
| 0xA5, ` ` |  0     |  FALSE   |
| 0xA6, ` ` |  0     |  FALSE   |
| 0xA7, ` ` |  0     |  FALSE   |
| 0xA8, ` ` |  0     |  FALSE   |
| 0xA9, ` ` |  0     |  FALSE   |
| 0xAA, ` ` |  0     |  FALSE   |
| 0xAB, ` ` |  0     |  FALSE   |
| 0xAC, ` ` |  0     |  FALSE   |
| 0xAD, ` ` |  0     |  FALSE   |
| 0xAE, ` ` |  0     |  FALSE   |
| 0xAF, ` ` |  0     |  FALSE   |
| 0xB0, ` ` |  0     |  FALSE   |
| 0xB1, ` ` |  0     |  FALSE   |
| 0xB2, ` ` |  0     |  FALSE   |
| 0xB3, ` ` |  0     |  FALSE   |
| 0xB4, ` ` |  0     |  FALSE   |
| 0xB5, ` ` |  0     |  FALSE   |
| 0xB6, ` ` |  0     |  FALSE   |
| 0xB7, ` ` |  0     |  FALSE   |
| 0xB8, ` ` |  0     |  FALSE   |
| 0xB9, ` ` |  0     |  FALSE   |
| 0xBA, ` ` |  0     |  FALSE   |
| 0xBB, ` ` |  0     |  FALSE   |
| 0xBC, ` ` |  0     |  FALSE   |
| 0xBD, ` ` |  0     |  FALSE   |
| 0xBE, ` ` |  0     |  FALSE   |
| 0xBF, ` ` |  0     |  FALSE   |
| 0xC0, ` ` |  0     |  FALSE   |
| 0xC1, ` ` |  0     |  FALSE   |
| 0xC2, ` ` |  0     |  FALSE   |
| 0xC3, ` ` |  0     |  FALSE   |
| 0xC4, ` ` |  0     |  FALSE   |
| 0xC5, ` ` |  0     |  FALSE   |
| 0xC6, ` ` |  0     |  FALSE   |
| 0xC7, ` ` |  0     |  FALSE   |
| 0xC8, ` ` |  0     |  FALSE   |
| 0xC9, ` ` |  0     |  FALSE   |
| 0xCA, ` ` |  0     |  FALSE   |
| 0xCB, ` ` |  0     |  FALSE   |
| 0xCC, ` ` |  0     |  FALSE   |
| 0xCD, ` ` |  0     |  FALSE   |
| 0xCE, ` ` |  0     |  FALSE   |
| 0xCF, ` ` |  0     |  FALSE   |
| 0xD0, ` ` |  0     |  FALSE   |
| 0xD1, ` ` |  0     |  FALSE   |
| 0xD2, ` ` |  0     |  FALSE   |
| 0xD3, ` ` |  0     |  FALSE   |
| 0xD4, ` ` |  0     |  FALSE   |
| 0xD5, ` ` |  0     |  FALSE   |
| 0xD6, ` ` |  0     |  FALSE   |
| 0xD7, ` ` |  0     |  FALSE   |
| 0xD8, ` ` |  0     |  FALSE   |
| 0xD9, ` ` |  0     |  FALSE   |
| 0xDA, ` ` |  0     |  FALSE   |
| 0xDB, ` ` |  0     |  FALSE   |
| 0xDC, ` ` |  0     |  FALSE   |
| 0xDD, ` ` |  0     |  FALSE   |
| 0xDE, ` ` |  0     |  FALSE   |
| 0xDF, ` ` |  0     |  FALSE   |
| 0xE0, ` ` |  0     |  FALSE   |
| 0xE1, ` ` |  0     |  FALSE   |
| 0xE2, ` ` |  0     |  FALSE   |
| 0xE3, ` ` |  0     |  FALSE   |
| 0xE4, ` ` |  0     |  FALSE   |
| 0xE5, ` ` |  0     |  FALSE   |
| 0xE6, ` ` |  0     |  FALSE   |
| 0xE7, ` ` |  0     |  FALSE   |
| 0xE8, ` ` |  0     |  FALSE   |
| 0xE9, ` ` |  0     |  FALSE   |
| 0xEA, ` ` |  0     |  FALSE   |
| 0xEB, ` ` |  0     |  FALSE   |
| 0xEC, ` ` |  0     |  FALSE   |
| 0xED, ` ` |  0     |  FALSE   |
| 0xEE, ` ` |  0     |  FALSE   |
| 0xEF, ` ` |  0     |  FALSE   |
| 0xF0, ` ` |  0     |  FALSE   |
| 0xF1, ` ` |  0     |  FALSE   |
| 0xF2, ` ` |  0     |  FALSE   |
| 0xF3, ` ` |  0     |  FALSE   |
| 0xF4, ` ` |  0     |  FALSE   |
| 0xF5, ` ` |  0     |  FALSE   |
| 0xF6, ` ` |  0     |  FALSE   |
| 0xF7, ` ` |  0     |  FALSE   |
| 0xF8, ` ` |  0     |  FALSE   |
| 0xF9, ` ` |  0     |  FALSE   |
| 0xFA, ` ` |  0     |  FALSE   |
| 0xFB, ` ` |  0     |  FALSE   |
| 0xFC, ` ` |  0     |  FALSE   |
| 0xFD, ` ` |  0     |  FALSE   |
| 0xFE, ` ` |  0     |  FALSE   |
| 0xFF, ` ` |  0     |  FALSE   |

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.