25

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?

Piccolo
  • 1,523
  • 2
  • 21
  • 36
Walidix
  • 1,177
  • 4
  • 15
  • 26
  • with sprintf, how to determine the size of buffer with platform-independent manner – Walidix Apr 25 '10 at 20:01
  • @Walidix the answer is probably limits.h : http://en.wikipedia.org/wiki/Limits.h – Andrei Ciobanu Apr 25 '10 at 20:03
  • 1
    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. – Carl Smotricz Apr 25 '10 at 20:05
  • 1
    @Walidix: You need to compute `log10(ULONG_MAX)`... – kennytm Apr 25 '10 at 20:09
  • A foolproof answer is `snprintf` if you have it. See my answer for a little more detail. – Carl Smotricz Apr 25 '10 at 20:09

6 Answers6

34
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);
jfs
  • 374,366
  • 172
  • 933
  • 1,594
7

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.

Carl Smotricz
  • 64,576
  • 17
  • 123
  • 163
  • Yes, i would use `snprintf`. It's Standard, and it provides support for completely solving this. – Johannes Schaub - litb Apr 25 '10 at 20:10
  • Contradicting your gravatar, +1 for sanity. – Tim Post Apr 25 '10 at 20:10
  • Printing a number is a case where you don't need `snprintf`; you can easily bound the size of buffer required. (Printing with `%s` OTOH, that requires caution.) – Donal Fellows Apr 25 '10 at 20:12
  • Many programmers will feel better specifying a very explicit upper bound with `snprintf` than using considerations about the sizes of numbers to mathematically establish such a bound or -worse, IMO- fiddling with logarithms to pre-calculate that size. – Carl Smotricz Apr 25 '10 at 20:17
5

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.

Andrew Barber
  • 38,454
  • 20
  • 92
  • 120
user2083050
  • 401
  • 4
  • 3
3
char buffer [50];

unsigned long a = 5;

int n=sprintf (buffer, "%lu", a);
2

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 longs, which can produce numbers as big as 10 digits.

See Carl Smotricz's answer for a better explanation of the issues involved.

MAK
  • 25,310
  • 10
  • 52
  • 84
1

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 );
     }
stacker
  • 66,311
  • 27
  • 138
  • 208