Have the user pass in the buffer to be written to, along with the size. Obviously, the function has to be renamed. Even this is a bit generic; it should perhaps be format_hash_to_hex_string() because of the hashid parameter.
int format_hex_string(unsigned char const *hash, hashid type, char *buffer, size_t buflen)
{
size_t n = mhash_get_block_size(type);
if (buflen < 2 * n + 1)
return -1;
for (size_t i = 0; i < n; i++)
sprintf(&buffer[2*i], "%.2X", hash[i]);
return 0;
}
Or, if you trust your users to provide a big enough buffer:
format_hex_string(unsigned char const *hash, hashid type, char *buffer)
{
size_t n = mhash_get_block_size(type);
for (size_t i = 0; i < n; i++)
sprintf(&buffer[2*i], "%.2X", hash[i]);
}
Or if you prefer bit twiddling (which probably is quicker than calling sprintf()):
int format_hex_string(unsigned char const *hash, hashid type, char *buffer, size_t buflen)
{
static char const hexdigits[] = "0123456789ABCDEF";
size_t n = mhash_get_block_size(type);
if (buflen < 2 * n + 1)
return -1;
for (size_t i = 0; i < n; i++)
{
*buffer++ = hexdigits[hash[i] >> 4];
*buffer++ = hexdigits[hash[i] & 0xF];
}
*buffer = '\0';
return 0;
}
To justify the generic name, it would be better to replace the hashid type parameter with a simple length (and you could then reasonably assume that the programmer knows that the buffer length must be at least 2 times the hash length):
int format_hex_string(unsigned char const *binbuffer, size_t binlen, char *hexbuffer)
{
static char const hexdigits[] = "0123456789ABCDEF";
for (size_t i = 0; i < binlen; i++)
{
*hexbuffer++ = hexdigits[binbuffer[i] >> 4];
*hexbuffer++ = hexdigits[binbuffer[i] & 0xF];
}
*hexbuffer = '\0';
}
This now is a general purpose function. And you could wrap it to specialize it for your hash formatting if you wanted to; the wrapper might save you writing a few calls to your mhash_get_block_size() function.
int n = mhash_get_block_size(type);and thenfor (int i = 0; i < n; i++)(or, if you're stuck with C89, you declareioutside the loop).