0

How can I convert a long variable to a char[] variable without using library functions?

colti
  • 393
  • 1
  • 15
  • 2
    C doesn't have a `string` type; do you want a C string or a C++ `std::string`? – Carl Norum Oct 03 '14 at 17:44
  • 1
    @AlterMann, `sprintf` is not a system call. – Carl Norum Oct 03 '14 at 17:46
  • 5
    All you need is division and modulo operations, and a knowledge of the character set. The only system call you need is the [`realloc`](http://man7.org/linux/man-pages/man3/realloc.3.html) function. – Some programmer dude Oct 03 '14 at 17:46
  • Your question is essentially asking how to implement a subset of the `sprintf` function. There are plenty of open-source implementations online; why not look at one of those? – Carl Norum Oct 03 '14 at 17:46
  • 1
    sprintf() is not a system call. I'd like to ask which OS's system calls you are targetting. Also, do you actually know what a system call is? – Ulrich Eckhardt Oct 03 '14 at 17:46
  • @CarlNorum My bad. A C string (char[]). – colti Oct 03 '14 at 17:46
  • @CarlNorum, Abhi, oops, sorry I misread the question, thanks – David Ranieri Oct 03 '14 at 17:47
  • AFAIK, there are no system calls for this. This isn't the kind of thing that an OS deals with. – Barmar Oct 03 '14 at 17:47
  • @JoachimPileborg You don't even need that. – fuz Oct 03 '14 at 17:47
  • you can write yourself one if your point is not using libraries. – Jason Hu Oct 03 '14 at 17:47
  • Looks like this is homework, so people are hesitant to just give you the answer. But look at peeling off one digit at a time (division and modulo), and then look at char and see how you can convert a digit to its char representation (through adding something to the digit...) – KathyA. Oct 03 '14 at 17:48
  • I recommend you remove the “system calls” part from your question unless you want joke-answers. – 5gon12eder Oct 03 '14 at 17:48
  • @JoachimPileborg i think `realloc` is actually a library function? – Jason Hu Oct 03 '14 at 17:49
  • @KathyA. Thank you. Just needed a little push in the right direction. – colti Oct 03 '14 at 17:50
  • `realloc` is really not needed for the maximum size of the representation has a reasonably small limit that is well-known at compile-time. Also, OP says he wants it in a `char[]`, so no memory allocation. – 5gon12eder Oct 03 '14 at 17:50
  • 1
    Your question is ambiguous. Are you trying to a) convert a `long` integer value from some calculations into a text representation suitable for displaying to the user, or b) get at the raw bytes making up that `long` value by using a `char[]` to get at individual bytes, or c) something else entirely... – twalberg Oct 03 '14 at 18:08
  • related: [how to print __uint128_t number using gcc?](http://stackoverflow.com/q/11656241/4279) – jfs Oct 03 '14 at 18:18

2 Answers2

2

Working example (1) - thread-safe, requires min. buffsize = 40.

static const char *
xllitoa(long long int x, char *buff)
{
        char *p = buff + 40;
        int sign = 0;
        *(p--) = 0;
        if (x < 0) sign = 1;
        else x = -x;
        do { *(p--) = -(x % 10) + '0'; x /= 10; } while(x);
        if (sign) *(p--) = '-';
        return (const char *)(p+1);
}

Working example (2) - not thread-safe

static const char *
xllitoa(long long int x)
{
        static char buff[40];
        char *p = buff + 40;
        int sign = 0;
        *(p--) = 0;
        if (x < 0) sign = 1;
        else x = -x;
        do { *(p--) = -(x % 10) + '0'; x /= 10; } while(x);
        if (sign) *(p--) = '-';
        return (const char *)(p+1);           
}

Many thanks to reviewers. Now it accepts LLONG_MAX and LLONG_MIN as well.

soerium
  • 573
  • 4
  • 12
  • 2
    +1 because IMHO it is the solution, but you do not use system calls ... was the question badly asked ? – Serge Ballesta Oct 03 '14 at 18:03
  • 1
    use `'0'` instead of `48`. C99 guarantees that `'1'` is next to `'0'`. `'0'` might differ from `48` (EBCDIC?). If `long long` is 128bit on some (future?) system then [you need bufsize=40 (including `'\0'` at the end)](http://stackoverflow.com/q/11656241/4279). Perheps some formula with `sizeof(long long)` should be used. – jfs Oct 03 '14 at 18:26
  • Note that in C99 you can document the 'buffer must be 32 characters' requirement explicitly (if obscurely) with: `const char *xllitoa(long long int x, char buff[static 32]) { … }`. – Jonathan Leffler Oct 03 '14 at 18:31
  • 1
    `xllitoa()` fails in 2 ways. 1) It does not terminate the buffer (But then OP said char array and not "string" Hmmmm. 2) It does not work for `LLONG_MIN`. – chux - Reinstate Monica Oct 03 '14 at 19:00
  • @JonathanLeffler Adding `static 32` to the array declaration does not trigger any type checking. The declarations `void foo(int a[static 32]);` and `void foo(int* a);` seem to be truly equivalent. – cmaster - reinstate monica Oct 03 '14 at 19:09
  • I did refactoring of example (1) on site and I didn't see that. Added null character - thanks for that. Yes, LLONG_MIN is an exception for this solution but the autor wanted it for LONG_MIN. – soerium Oct 03 '14 at 19:17
  • @cmaster: that is why I said 'document'. It promises the compiler that when the function is called, it can safely assume there are (at least) 32 bytes in the array pointed to by `a`. Whether the compiler can make any use of the remains to be seen, but the notation is there. (I don't know why it was added; it doesn't seem particularly useful to me, but there must have been a reason to recycle the keyword `static` yet again. There is a discussion of the facility in the [C99 Rationale](http://www.open-std.org/jtc1/sc22/wg14/www/C99RationaleV5.10.pdf) in §6.7.5.2 _Array declarators_.) – Jonathan Leffler Oct 03 '14 at 19:20
  • @JonathanLeffler I see. Still, `static` is neither required for documentation nor for optimization, for these two purposes declaring `void foo(int a[32])` and looping with `for(int i = 0; i < 32; i++)` would be enough. The real effect of `static` in this context seems to be that it immediately calls "undefined behavior" if `a` points to NULL or the array it points to is too short. That is, the compiler is allowed to optimize away the `if()` statement in `void foo(int a[static 32]) { if(!a) return; ... }` which makes the `static` dangerous to use without thinking about it. – cmaster - reinstate monica Oct 03 '14 at 20:18
  • 2
    @soerium C specifies `LLONG_MIN <= LONG_MIN`. Since they could be the same value (they are on my gcc machine), failing `LLONG_MIN` as this code does, also can fail OP's `LONG_MIN`. Going to `long long` to avoid a problem with `LONG_MIN` does not always work. – chux - Reinstate Monica Oct 03 '14 at 22:44
  • Minor: Using a qualifier of `const` unnecessarily restricts the return value in `xllitoa(long long int x, char *buff)`. – chux - Reinstate Monica Oct 03 '14 at 22:48
2

After accept answer that works for all values LONG_MIN to LONG_MAX.

This uses a helper function to recursive work with negative values of n. By using negative values, there is no problem with LONG_MIN.

static char *ltostr_helper(long n, char *dest) {
  if (n <= -10)
    dest = ltostr_helper(n / 10, dest);
  *dest++ = (char) ('0' - n % 10);
  return dest;  // return pointer to end
}

void ltostr(long n, char *dest) {
  if (n < 0) {
    *dest++ = '-';
  } else {
    n = -n;
  }
  *ltostr_helper(n, dest) = '\0';
}

int main(void) {
  char buf[sizeof(long) * CHAR_BIT /3 + 3];//  size buffer to our needs
  ltostr(0, buf); printf("%s\n", buf);
  ltostr(123, buf); printf("%s\n", buf);
  ltostr(-123, buf); printf("%s\n", buf);
  ltostr(LONG_MAX, buf); printf("%s\n", buf);
  ltostr(LONG_MIN, buf); printf("%s\n", buf);
  return 0;
}

Output
0
123  
-123  
9223372036854775807  
-9223372036854775808  
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • +1 for `sizeof(long)`. The negative values trick works for any allowed `long` representation: [two's complement, one's complement, sign/magnitude representations](http://stackoverflow.com/a/3952262/4279). – jfs Oct 04 '14 at 09:18