Reputation: 1277
In the C language, how do I convert unsigned long value to a string (char *) and keep my source code portable or just recompile it to work on other platform (without rewriting code?
For example, if I have sprintf(buffer, format, value)
, how do I determine the size of buffer with platform-independent manner?
Upvotes: 27
Views: 117904
Reputation: 153547
... 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
Upvotes: 0
Reputation: 431
you can write a function which converts from unsigned long to str, similar to ltostr library function.
char *ultostr(unsigned long value, char *ptr, int base)
{
unsigned long t = 0, res = 0;
unsigned long tmp = value;
int count = 0;
if (NULL == ptr)
{
return NULL;
}
if (tmp == 0)
{
count++;
}
while(tmp > 0)
{
tmp = tmp/base;
count++;
}
ptr += count;
*ptr = '\0';
do
{
res = value - base * (t = value / base);
if (res < 10)
{
* -- ptr = '0' + res;
}
else if ((res >= 10) && (res < 16))
{
* --ptr = 'A' - 10 + res;
}
} while ((value = t) != 0);
return(ptr);
}
you can refer to my blog here which explains implementation and usage with example.
Upvotes: 5
Reputation: 26586
Try using sprintf
:
unsigned long x=1000000;
char buffer[21];
sprintf(buffer,"%lu", x);
Edit:
Notice that you have to allocate a buffer in advance, and have no idea how long the numbers will actually be when you do so. I'm assuming 32bit long
s, which can produce numbers as big as 10 digits.
See Carl Smotricz's answer for a better explanation of the issues involved.
Upvotes: 2
Reputation: 414345
const int n = snprintf(NULL, 0, "%lu", ulong_value);
assert(n > 0);
char buf[n+1];
int c = snprintf(buf, n+1, "%lu", ulong_value);
assert(buf[n] == '\0');
assert(c == n);
Upvotes: 36
Reputation: 67760
The standard approach is to use sprintf(buffer, "%lu", value);
to write a string rep of value
to buffer
. However, overflow is a potential problem, as sprintf
will happily (and unknowingly) write over the end of your buffer.
This is actually a big weakness of sprintf, partially fixed in C++ by using streams rather than buffers. The usual "answer" is to allocate a very generous buffer unlikely to overflow, let sprintf output to that, and then use strlen to determine the actual string length produced, calloc a buffer of (that size + 1) and copy the string to that.
This site discusses this and related problems at some length.
Some libraries offer snprintf
as an alternative which lets you specify a maximum buffer size.
Upvotes: 7
Reputation: 68962
For a long value you need to add the length info 'l' and 'u' for unsigned decimal integer,
as a reference of available options see sprintf
#include <stdio.h>
int main ()
{
unsigned long lval = 123;
char buffer [50];
sprintf (buffer, "%lu" , lval );
}
Upvotes: 1
Reputation: 515
char buffer [50];
unsigned long a = 5;
int n=sprintf (buffer, "%lu", a);
Upvotes: 3