# Convert a hexadecimal string to an integer efficiently in C?

24

In C, what is the most efficient way to convert a string of hex digits into a binary `unsigned int` or `unsigned long`?

For example, if I have `0xFFFFFFFE`, I want an `int` with the base10 value `4294967294`.

c
performance
hex
strtol

39
32

Edit: Now compatible with MSVC, C++ and non-GNU compilers (see end).

The question was "most efficient way." The OP doesn't specify platform, he could be compiling for a RISC based ATMEL chip with 256 bytes of flash storage for his code.

For the record, and for those (like me), who appreciate the difference between "the easiest way" and the "most efficient way", and who enjoy learning...

``````static const long hextable[] = {
[0 ... 255] = -1, // bit aligned access into this table is considerably
['0'] = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, // faster for most modern processors,
['A'] = 10, 11, 12, 13, 14, 15,       // for the space conscious, reduce to
['a'] = 10, 11, 12, 13, 14, 15        // signed char.
};

/**
* @brief convert a hexidecimal string to a signed long
* will not produce or process negative numbers except
* to signal error.
*
* @param hex without decoration, case insensitive.
*
* @return -1 on error, or result (max (sizeof(long)*8)-1 bits)
*/
long hexdec(unsigned const char *hex) {
long ret = 0;
while (*hex && ret >= 0) {
ret = (ret << 4) | hextable[*hex++];
}
return ret;
}
``````

It requires no external libraries, and it should be blindingly fast. It handles uppercase, lowercase, invalid characters, odd-sized hex input (eg: 0xfff), and the maximum size is limited only by the compiler.

For non-GCC or C++ compilers or compilers that will not accept the fancy hextable declaration.

Replace the first statement with this (longer, but more conforming) version:

``````static const long hextable[] = {
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1, 0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,-1,10,11,12,13,14,15,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
};
``````
19

Try this:

``````#include <stdio.h>
int main()
{
char s[] = "fffffffe";
int x;
sscanf(s, "%x", &x);
printf("%u\n", x);
}
``````
8

If you don't have the stdlib then you have to do it manually.

``````unsigned long hex2int(char *a, unsigned int len)
{
int i;
unsigned long val = 0;

for(i=0;i<len;i++)
if(a[i] <= 57)
val += (a[i]-48)*(1<<(4*(len-1-i)));
else
val += (a[i]-55)*(1<<(4*(len-1-i)));

return val;
}
``````

Note: This code assumes uppercase A-F. It does not work if len is beyond your longest integer 32 or 64bits, and there is no error trapping for illegal hex characters.

6

For AVR Microcontrollers I wrote the following function, including relevant comments to make it easy to understand:

``````/**
* hex2int
* take a hex string and convert it to a 32bit number (max 8 hex digits)
*/
uint32_t hex2int(char *hex) {
uint32_t val = 0;
while (*hex) {
// get current character then increment
char byte = *hex++;
// transform hex character to the 4bit equivalent number, using the ascii table indexes
if (byte >= '0' && byte <= '9') byte = byte - '0';
else if (byte >= 'a' && byte <='f') byte = byte - 'a' + 10;
else if (byte >= 'A' && byte <='F') byte = byte - 'A' + 10;
// shift 4 to make space for new digit, and add the 4 bits of the new digit
val = (val << 4) | (byte & 0xF);
}
return val;
}
``````

Example:

``````char *z ="82ABC1EF";
uint32_t x = hex2int(z);
printf("Number is [%X]\n", x);
``````
5

As if often happens, your question suffers from a serious terminological error/ambiguity. In common speech it usually doesn't matter, but in the context of this specific problem it is critically important.

You see, there's no such thing as "hex value" and "decimal value" (or "hex number" and "decimal number"). "Hex" and "decimal" are properties of representations of values. Meanwhile, values (or numbers) by themselves have no representation, so they can't be "hex" or "decimal". For example, `0xF` and `15` in C syntax are two different representations of the same number.

I would guess that your question, the way it is stated, suggests that you need to convert ASCII hex representation of a value (i.e. a string) into a ASCII decimal representation of a value (another string). One way to do that is to use an integer representation as an intermediate one: first, convert ASCII hex representation to an integer of sufficient size (using functions from `strto...` group, like `strtol`), then convert the integer into the ASCII decimal representation (using `sprintf`).

If that's not what you need to do, then you have to clarify your question, since it is impossible to figure it out from the way your question is formulated.

3

Hexadecimal to decimal. Don't run it on online compilers, because it won't work.

``````#include<stdio.h>
void main()
{
unsigned int i;
scanf("%x",&i);
printf("%d",i);
}
``````
2

@Eric

Why is a code solution that works getting voted down? Sure, it's ugly and might not be the fastest way to do it, but it's more instructive that saying "strtol" or "sscanf". If you try it yourself you will learn something about how things happen under the hood.

I don't really think your solution should have been voted down, but my guess as to why it's happening is because it's less practical. The idea with voting is that the "best" answer will float to the top, and while your answer might be more instructive about what happens under the hood (or a way it might happen), it's definitely not the best way to parse hex numbers in a production system.

Again, I don't think there's anything wrong with your answer from an educational standpoint, and I certainly wouldn't (and didn't) vote it down. Don't get discouraged and stop posting just because some people didn't like one of your answers. It happens.

I doubt my answer makes you feel any better about yours being voted down, but I know it's especially not fun when you ask why something's being voted down and no one answers.

2

For larger Hex strings like in the example I needed to use strtoul.

answered on Stack Overflow Aug 14, 2008 by (unknown user)
1

@Eric

I was actually hoping to see a C wizard post something really cool, sort of like what I did but less verbose, while still doing it "manually".

Well, I'm no C guru, but here's what I came up with:

``````unsigned int parseHex(const char * str)
{
unsigned int val = 0;
char c;

while(c = *str++)
{
val <<= 4;

if (c >= '0' && c <= '9')
{
val += c & 0x0F;
continue;
}

c &= 0xDF;
if (c >= 'A' && c <= 'F')
{
val += (c & 0x07) + 9;
continue;
}

errno = EINVAL;
return 0;
}

return val;
}
``````

I originally had more bitmasking going on instead of comparisons, but I seriously doubt bitmasking is any faster than comparison on modern hardware.

1

Why is a code solution that works getting voted down? Sure, it's ugly ...

Perhaps because as well as being ugly it isn't educational and doesn't work. Also, I suspect that like me, most people don't have the power to edit at present (and judging by the rank needed - never will).

The use of an array can be good for efficiency, but that's not mentioned in this code. It also takes no account of upper and lower case so it does not work for the example supplied in the question. FFFFFFFE

1

Try this to Convert from Decimal to Hex

``````    #include<stdio.h>
#include<conio.h>

int main(void)
{
int count=0,digit,n,i=0;
int hex;
clrscr();
printf("enter a number   ");
scanf("%d",&n);

if(n<10)
{
printf("%d",n);
}

switch(n)
{
case 10:
printf("A");
break;
case 11:
printf("B");
break;
case 12:
printf("B");
break;
case 13:
printf("C");
break;
case 14:
printf("D");
break;
case 15:
printf("E");
break;
case 16:
printf("F");
break;
default:;
}

while(n>16)
{
digit=n%16;
hex[i]=digit;
i++;
count++;
n=n/16;
}

hex[i]=n;

for(i=count;i>=0;i--)
{
switch(hex[i])
{
case 10:
printf("A");
break;
case 11:
printf("B");
break;
case 12:
printf("C");
break;
case  13:
printf("D");
break;
case 14:
printf("E");
break;
case 15:
printf("F");
break;
default:
printf("%d",hex[i]);
}
}

getch();

return 0;
}
``````
1
``````#include "math.h"
#include "stdio.h"
///////////////////////////////////////////////////////////////
//  The bits arg represents the bit say:8,16,32...
/////////////////////////////////////////////////////////////
volatile long Hex_To_Int(long Hex,char bits)
{
long Hex_2_Int;
char byte;
Hex_2_Int=0;

for(byte=0;byte<bits;byte++)
{
if(Hex&(0x0001<<byte))
Hex_2_Int+=1*(pow(2,byte));
else
Hex_2_Int+=0*(pow(2,byte));
}

return Hex_2_Int;
}
///////////////////////////////////////////////////////////////
//
/////////////////////////////////////////////////////////////

void main (void)
{
int Dec;
char Hex=0xFA;
Dec= Hex_To_Int(Hex,8);  //convert an 8-bis hexadecimal value to a number in base 10
printf("the number is %d",Dec);
}
``````
1

As written before, the efficiency basically depends on what one is optimizing for.

When optiming for lines of code, or just working in environment without fully-equipped standard library one quick and dirty option could be:

``````// makes a number from two ascii hexa characters
int ahex2int(char a, char b){

a = (a <= '9') ? a - '0' : (a & 0x7) + 9;
b = (b <= '9') ? b - '0' : (b & 0x7) + 9;

return (a << 4) + b;
}
``````

... more in similar thread here: https://stackoverflow.com/a/58253380/5951263

-2

In C you can convert a hexadecimal number to decimal in many ways. One way is to cast the hexadecimal number to an integer. I personally found this to be simple and small.

Here is an sample code for converting a Hexadecimal number to a Decimal number with the help of casting.

``````#include <stdio.h>

int main(){
unsigned char Hexadecimal = 0x6D;   //example hex number
int Decimal = 0;    //decimal number initialized to 0

printf("The decimal number is %d\n", Decimal);  //output
return 0;
}
``````
-3

This currently only works with lower case but its super easy to make it work with both.

``````cout << "\nEnter a hexadecimal number: ";
cin >> hexNumber;
orighex = hexNumber;

strlength = hexNumber.length();

for (i=0;i<strlength;i++)
{
hexa = hexNumber.substr(i,1);
if ((hexa>="0") && (hexa<="9"))
{
//cout << "This is a numerical value.\n";
}
else
{
//cout << "This is a alpabetical value.\n";
if (hexa=="a"){hexa="10";}
else if (hexa=="b"){hexa="11";}
else if (hexa=="c"){hexa="12";}
else if (hexa=="d"){hexa="13";}
else if (hexa=="e"){hexa="14";}
else if (hexa=="f"){hexa="15";}
else{cout << "INVALID ENTRY! ANSWER WONT BE CORRECT\n";}
}
//convert from string to integer

hx = atoi(hexa.c_str());
finalhex = finalhex + (hx*pow(16.0,strlength-i-1));
}
cout << "The hexadecimal number: " << orighex << " is " << finalhex << " in decimal.\n";
``````

User contributions licensed under CC BY-SA 3.0