Thanks for that great link explaining radix sort. Here is a more generic C version for the same algorithm.

You can configure the number of buckets using RADIX_BIT_COUNT. Typically this could be either 2, 4 or 8.
Calculation of the bucket number for a key can be done relative to the smallest element -- (arr[i] - small) >> shift) & RADIX_MASK
/*************************************************/
/* Configuration Macros */
/*************************************************/
#define RADIX_BIT_COUNT 8
#define RADIX_MASK ((1 << RADIX_BIT_COUNT) - 1)
/***********************************************************************/
/* RadixSort: Run a radix sort */
/***********************************************************************/
void RadixSort(int *a, int len)
{
int rcount[RADIX_MASK + 1] = {0};
int i, roff, small, large, shift = 0;
int *arr = a, *arr2, *ta;
/* Allocate the sort array */
if ((ta = arr2 = malloc(sizeof(int) * len)) == NULL)
return;
/* Find the smallest and largest element */
for (i = 0; i < len; ++i) {
small = (i == 0) || small > a[i] ? a[i] : small;
large = (i == 0) || large < a[i] ? a[i] : large;
}
/* Loop until we are not done! */
while (shift < (sizeof(int) * 8) && ((large - small) >> shift) != 0)
{
/* Generate the number of entries for each bucket, then accumulate
their counts */
for (i = 0; i < len; ++i)
rcount[((arr[i] - small) >> shift) & RADIX_MASK]++;
for (i = 1; i < RADIX_MASK + 1; ++i)
rcount[i] += rcount[i - 1];
/* Move the contents creating buckets sorted based on the
corresponding LSBs. Note that we are traversing from the back
of the array, this means the larger entries go to larger
offsets within the buckets. */
for (i = len - 1; i >= 0; --i){
/* Calculate the bucket for the value. */
roff = ((arr[i] - small) >> shift) & RADIX_MASK;
arr2[rcount[roff] - 1] = arr[i];
rcount[roff]--; // decrement the bucket offset
}
/* Swap the arrays & Reset counters. */
arr2 = (arr2 == a) ? ta : a;
arr = (arr == a) ? ta : a;
memset(rcount, 0, sizeof(int) * (RADIX_MASK + 1));
shift += RADIX_BIT_COUNT;
}
/* If needed, make a copy of the array */
if (arr != a) {
memcpy(a, arr, sizeof(int) * len);
arr2 = arr;
}
/* Live free */
free(arr2);
}