... how do I determine the size of buffer with platform-independent manner?
One of the challenges of converting a unsigned long
to a string is how to determine the string size that is needed.
Repeatedly divide the value by 10 until 0 to find size_needed
.
value_copy = value;
unsigned size_needed = 1; // For the null character.
if (value_copy < 0) size_needed++; // Only needed for signed types.
do {
size_needed++; // Add 1 per digit.
value_copy /= 10;
} while (value_copy != 0);
Find the string length of ULONG_MAX
.
Start with the nifty IMAX_BITS(m)
which returns the number of bits in a Mersenne Number like ULONG_MAX
. (This give us the max bit width even if the type has padding.) Then scale by log102 (0.301...) to find the number of decimal digits and add 2 for rounding and the null character.
#define IMAX_BITS(m) ((m)/((m)%255+1) / 255%255*8 + 7-86/((m)%255+12))
#define LOG2_10_N 28
#define LOG2_10_D 93
#define UNSIGNED_LONG_STRING_SIZE (IMAX_BITS(ULONG_MAX)*LOG2_10_N/LOG2_10_D + 2)
// Slightly different for signed types, one more for the sign:
#define SIGNED_LONG_STRING_SIZE (IMAX_BITS( LONG_MAX)*LOG2_10_N/LOG2_10_D + 3)
Armed with the string size, there are many possible next steps. I like using C99's (and later) compound literal to form the needed space. The space is valid until the end of the block.
char *unsigned_long_to_string(char *dest, unsigned long x) {
sprintf(dest, "%lu", x);
return dest;
}
// Compound literal v-----------------------------------v
#define UNSIGNED_LONG_TO_STRING(u) unsigned_long_to_string((char [UNSIGNED_LONG_STRING_SIZE]){0}, (u))
int main(void) {
puts(UNSIGNED_LONG_TO_STRING(42));
puts(UNSIGNED_LONG_TO_STRING(ULONG_MAX));
}
Output
42
18446744073709551615 // This varies