I have hexadecimal values stored as characters:
char A = \'0\';
char B = \'6\';
char C = \'E\';
... I need them coverted to integers. I kno
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
.
You could try strtol
. But strtol
needs a 0 terminated char *
, so:
long x = strtol((char[]){A, 0}, NULL, 16);
#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;
}
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);
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);
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 ) ];