<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Involution &#187; stackoverflow</title>
	<atom:link href="http://involution.com/category/stackoverflow/feed/" rel="self" type="application/rss+xml" />
	<link>http://involution.com</link>
	<description>Tony Perrie's Weblog</description>
	<lastBuildDate>Sat, 24 Jul 2010 06:54:04 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Converting a char* to a hexadecimal char* using C</title>
		<link>http://involution.com/2008/09/16/converting-a-char-to-a-hexadecimal-char-using-c/</link>
		<comments>http://involution.com/2008/09/16/converting-a-char-to-a-hexadecimal-char-using-c/#comments</comments>
		<pubDate>Wed, 17 Sep 2008 01:45:38 +0000</pubDate>
		<dc:creator>Tony Perrie</dc:creator>
				<category><![CDATA[C]]></category>
		<category><![CDATA[stackoverflow]]></category>
		<category><![CDATA[C++]]></category>

		<guid isPermaLink="false">http://involution.com/?p=1174</guid>
		<description><![CDATA[Back when I used to work on microprocessors, I would find an infinity of half-working hex-to-decimal converters lurking around in various C repositories. At first glance, it&#8217;s such a trivial function to write. Often, in a vain effort to &#8220;keep it simple&#8221;, programmers go off half-cocked and partially implement another bad version snprintf or strtol. [...]]]></description>
			<content:encoded><![CDATA[<p>Back when I used to work on microprocessors, I would find an infinity of half-working hex-to-decimal converters lurking around in various C repositories.  At first glance, it&#8217;s such a trivial function to write.  Often, in a vain effort to &#8220;keep it simple&#8221;, programmers go off half-cocked and partially implement another bad version <code>snprintf</code> or <code>strtol</code>.</p>
<p>While it is appears trivial to implement this, making it work correctly for all integer types on your platform is rather tricky.  That&#8217;s why the POSIX <code>string.h</code> functions exist.  Unless you&#8217;re feeling brave or stupid, DON&#8217;T REWRITE THESE!</p>
<p>Last night, I stumbled across something similar on <a href="http://stackoverflow.com">Stack Overflow</a>. The particular <a href="http://stackoverflow.com/questions/69115/char-to-hex-string-exercise#70254">question</a> was a slight variation on the hex conversion formatting provided by <code>snprintf</code>.  The caveat is that this new function must convert an arbitrary length character array into a character array of hexadecimal ASCII codes as fast as possible.  For example, &#8220;<code>DO NOT WANT</code>&#8221; becomes &#8220;<code>444F204E4F542057</code>&#8221; since <code>D</code> corresponds to <code>0x44</code>, <code>O</code> to <code>0x4F</code> and so on.</p>
<p>One solution is to take an input character array, cast it to an array of unsigned long longs, and convert the integers one-at-a-time.  This is a reasonable strategy, however it works better on PowerPC because x86 is a little-endian architecture that reverses the byte order.</p>
<p>Let me explain.  In C, you can cast pointers with reckless abandon.  Character arrays can become integer arrays and then be converted back into character arrays again.  To C, it&#8217;s all just arrays of bytes.  You can make those bytes into whatever you want.  Consider the following.</p>
<pre>
  char a[] = "DO NOT WANT";
  size_t length = strlen(a);
  printf("a, living a normal life as a char* ----> %s\n", a);
  printf("a, disguised as an unsigned long long -> %08llX\n", *((unsigned long long*)a));
  // outputs
  // a, living a normal life as a char* ----------> DO NOT WANT
  // a, disguised as an unsigned long long -------> 5720544F4E204F44
  // the bytes are reordered on x86, a should be -> 444F204E4F542057
</pre>
<p>Unfortunately, it&#8217;s actually slower to iteratively call <code>snprintf</code> with a 64-bit stride than it is to just loop through character array one-byte-at-a-time and append the hexadecimal characters to the result.  Also, on x86 you have to reverse the byte order of each <code>unsigned long long</code> with <code>htonl</code>.  </p>
<p>So, back to the drawing board.  The original code had a 16 entry array that mapped individual hexadecimal digits to their character equivalents.   This can be improved to use a 255 entry array that maps entire bytes back to its character equivalent.  It can be initialized programatically as follows.</p>
<pre>
  for(int i=0; i<256; i++) {
    snprintf(_hex2asciiU_value[i], 3,"%02X", i);
  }
</pre>
<p>This look-up routine is very fast.  We cast the bytes back into its composite hexadecimal digits by simply performing a read from memory.  This is what everything looks like in a runnable C program. </p>
<pre>
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

char* char_to_hex( const unsigned char* p_array, unsigned int p_array_len, char** hex2ascii) {
    unsigned char* str = malloc(p_array_len*2+1);
    str[p_array_len*2] = '\0';
    const unsigned char* p_end = p_array + p_array_len;
    size_t pos=0;
    const unsigned char* p;
    for( p = p_array; p != p_end; p++, pos+=2 ) {
       str[pos] = hex2ascii[*p][0];
       str[pos+1] = hex2ascii[*p][1];
    }
    return (char*)str;
}

int main() {
  size_t hex2ascii_len = 256;
  char** hex2ascii;
  int i;
  hex2ascii = malloc(hex2ascii_len*sizeof(char*));
  for(i=0; i&lt;hex2ascii_len; i++) {
    hex2ascii[i] = malloc(3*sizeof(char));
    snprintf(hex2ascii[i], 3,"%02X", i);
  }
  size_t len = 8;
  const unsigned char a[] = "DO NOT WANT";
  printf("%s\n", char_to_hex((const unsigned char*)a, len, (char**)hex2ascii));
}
</pre>
<p>This is the runtime difference between the original implementation and the one shown above.</p>
<p><img src="/images/char2hex.png" width="440"/></p>
]]></content:encoded>
			<wfw:commentRss>http://involution.com/2008/09/16/converting-a-char-to-a-hexadecimal-char-using-c/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>
