Convert a hexadecimal string to an integer efficiently in C?

Question!

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.



Answers

Edit: Not compatible with MSVC. :(

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 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);

Will output: enter image description here

By : radhoo


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.

By : AnT


This video can help you solving your question :)
By: admin