Walidix
Walidix

Reputation: 1277

How to convert unsigned long to string

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

Answers (7)

chux
chux

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.

  • Dynamically

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);
  • Worse case

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

user2083050
user2083050

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

MAK
MAK

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

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

Upvotes: 2

jfs
jfs

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

Carl Smotricz
Carl Smotricz

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

stacker
stacker

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

Jeffrey Vandenborne
Jeffrey Vandenborne

Reputation: 515

char buffer [50];

unsigned long a = 5;

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

Upvotes: 3

Related Questions