2

Im working with a embedded system and I need implement a way to convert long long to char.

The problem is that I can not use sprintf in this system to do that, so im looking for alternative ways/functions to implement this.

Suggestions of implementations for LongLongToChar function are welcome.

Manuel Cobra
  • 67
  • 1
  • 6

2 Answers2

2

Google "itoa". There are many variations. Here's an example.

char* itoa(int val, int base){

    static char buf[32] = {0};

    int i = 30;

    for(; val && i ; --i, val /= base)

        buf[i] = "0123456789abcdef"[val % base];

    return &buf[i+1];

}

Specifically, here's an 'lltoa'.

#include <stdio.h>
#include <limits.h>


char* lltoa(long long val, int base){

    static char buf[64] = {0};

    int i = 62;
    int sign = (val < 0);
    if(sign) val = -val;

    if(val == 0) return "0";

    for(; val && i ; --i, val /= base) {
        buf[i] = "0123456789abcdef"[val % base];
    }

    if(sign) {
        buf[i--] = '-';
    }
    return &buf[i+1];

}

int main() {
    long long a = LLONG_MAX;
    long long b = LLONG_MIN + 1;
    long long c = 23;

    printf("%ld\n", sizeof(a));
    printf("max '%s'\n", lltoa(a, 10));
    printf("min '%s'\n", lltoa(b, 10));
    printf("-1  '%s'\n", lltoa((long long)-1, 10));
    printf("23  '%s'\n", lltoa(c, 10));
}
Charlie Burns
  • 6,994
  • 20
  • 29
  • You probably want base = 10. That would the same as %d in sprintf. Be careful of the buffer size and don't forget the minus sign. – Charlie Burns Sep 17 '13 at 19:53
  • @chux, good point. Thanks. That's embarrassing. That's what I get for copying code. – Charlie Burns Sep 17 '13 at 20:33
  • @Charlie Burns `long long` is at least 64 bits and with base 2, you might want `buf[64]` & `i = 30+32`. – chux - Reinstate Monica Sep 17 '13 at 20:39
  • @ManuelCobra: If you don't need base 10 (for users) you should consider sticking with base 16 (hexadecimal) because the "divides" will be shifts which will be far cheaper on an embedded MCU than divides (which will have to be done by library routines imported by the compiler). If you can't fit `sprintf` you probably don't want to drag in big integer divides either. – Ben Jackson Sep 17 '13 at 20:42
  • @Ben Jackson Concur that "big integer divide" may be expensive in time in embedded, but `sprintf` can be _huge_ both in space and time. Knowing OP's space/time needs would help steer the issue. – chux - Reinstate Monica Sep 17 '13 at 20:51
  • probably lltoa is what i need. I now just fix the following erros: Undefined external symbol "__div64s" and Undefined external symbol "__mod64s". What could be? – Manuel Cobra Sep 17 '13 at 21:13
  • i tested the code online and works well, now i just need to find a fix for the two problems that i still have. Thanks. – Manuel Cobra Sep 17 '13 at 21:22
  • Seems like your system is lacking a 64 bit divide and 64 bit modulo. – Charlie Burns Sep 17 '13 at 21:22
  • See if your c library includes lldiv(). If so, use the solution by chux below. – Charlie Burns Sep 17 '13 at 21:33
  • @ManuelCobra: There is no particular base for `long long int` (other than the raw binary used in its representation). You've *converting* the raw value to human-readable form. Use a base (most likely 10 or 16) that best suits your purposes. – Keith Thompson Sep 18 '13 at 00:23
2

Use lldiv(), saves CPU ticks over separate / and %.
Works well over entire long long range including 0 and that pesky LONG_LONG_MIN.

const char *ToString(long long i) {
  // static char buffer[sizeof(i)*3 + 1];  // Size could be a bit tighter
  static char buffer[(sizeof(i)*CHAR_BIT - 1)*28/93 + 3]; // 28/93 is about log10(2).
  char *p = &buffer[sizeof(buffer)] - 1;
  *p = '\0';
  lldiv_t qr;
  qr.quot = i;
  do {
    qr = lldiv(qr.quot, 10);
    *(--p) = abs(qr.rem) + '0';
  } while (qr.quot);
  if (i < 0) {
    *(--p) = '-';
  }
  return p;
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256