1

What is the clean way to do that in C?

wchar_t* ltostr(long value) {
    int size = string_size_of_long(value);
    wchar_t *wchar_copy = malloc(value * sizeof(wchar_t));
    swprintf(wchar_copy, size, L"%li", self);
    return wchar_copy;
}

The solutions I came up so far are all rather ugly, especially allocate_properly_size_whar_t uses double float base math.

camillobruni
  • 2,298
  • 16
  • 26
  • You want `malloc(size * sizeof(wchar_t))`, or possibly `(size+1)` depending on whether your hypothesised `string_size_of_long()` accounts for the null terminator. – Oliver Charlesworth Jun 08 '10 at 16:08
  • 1
    Do you want a `char*` or a `wchar_t*`? Your title says `char*`, but your example is for `wchar_t*`. – JSBձոգչ Jun 08 '10 at 16:09
  • wchar or char is just a matter of a constant. the problem is how to get the upper bound of number of characters for a specific long. – camillobruni Jun 22 '10 at 18:29

6 Answers6

4

A long won't have more than 64 digits on any platform (actually less than that, but I'm too lazy to figure out what the actual minimum is now). So just print to a fixed-size buffer, then use wcsdup rather than trying to calculate the length ahead of time.

wchar_t* ltostr(long value) {
    wchar_t buffer[ 64 ] = { 0 };
    swprintf(buffer, sizeof(buffer), L"%li", value);
    return wcsdup(buffer);
}

If you want a char*, it's trivial to translate the above:

char* ltostr(long value) {
    char buffer[ 64 ] = { 0 };
    snprintf(buffer, sizeof(buffer), "%li", value);
    return strdup(buffer);
}

This will be faster and less error-prone than calling snprintf twice, at the cost of a trivial amount of stack space.

JSBձոգչ
  • 40,684
  • 18
  • 101
  • 169
  • Not a good answer, partly because not a good question to begin with. If this function gets called over and over again, memory leaking will keep happening over again and again, with no bound. (I didn't downvote, someone else did). – Kevin Le - Khnle Jun 08 '10 at 16:10
  • Note that `wcsdup` et al are not ANSI compliant (AFAIK). – Oliver Charlesworth Jun 08 '10 at 16:11
  • @Khnle, it doesn't leak so long as the caller frees the returned string. I thought that was too basic to point out. – JSBձոգչ Jun 08 '10 at 16:13
  • How will memory leak? There's no memory leak. Function returns a newly-allocated buffer, which caller is responsible for freeing. There's nothing wrong with it. – el.pescado - нет войне Jun 08 '10 at 16:14
  • @JS Bangs, I didn't downvote your answer. I think it's better to re-write with the buffer passed in as an argument. I don't think it's a good idea to have malloc done in one place and free in another. – Kevin Le - Khnle Jun 08 '10 at 16:18
  • 1
    @Khnle, sure. But if you require the caller to pass in a buffer, then all that's left is a one-line wrapper for `snprintf`, which hardly seems worth the effort. – JSBձոգչ Jun 08 '10 at 16:24
  • 1
    @JS Bangs: assuming `long` is not bigger than 128 bit (which should be checked at compile time via `#if`/`#error`), a buffer of size 41 is large enough, as `ceil(lg 2^127) = 39`, plus 2 for sign and terminator – Christoph Jun 08 '10 at 16:56
  • @JS Bangs: If you have done that much harder work, there was no doubt you wouldn't know the minor thing. I vote up on your answer. – Kevin Le - Khnle Jun 08 '10 at 17:30
  • there's a possible buffer overflow in the wide-char version: afaik the call should read `swprintf(buffer, sizeof buffer / sizeof *buffer, L"%li", value)` because `swprintf()` expects the number of wide-chars in and not the byte-size of the buffer – Christoph Jun 08 '10 at 19:10
  • nice solution, still one issue left: the string returned is longer than the actual 'value', simple cropping will do it. – camillobruni Jun 08 '10 at 20:57
  • @dh82, the string returned is not longer than the actual value. Think about what `strdup` does to determine what to allocate. – JSBձոգչ Jun 08 '10 at 21:17
  • ah indeed, didnt check that :) – camillobruni Jun 22 '10 at 18:30
3
int charsRequired = snprintf(NULL, 0, "%ld", value) + 1;
char *long_str_buffer = malloc(charsRequired);
snprintf(long_str_buffer, charsRequired, "%ld", value);
Matthew Flaschen
  • 278,309
  • 50
  • 514
  • 539
2

The maximum number of digits is given by ceil(log10(LONG_MAX)). You can precompute this value for the most common ranges of long using the preprocessor:

#include <limits.h>

#if LONG_MAX < 1u << 31
#define LONG_MAX_DIGITS 10
#elif LONG_MAX < 1u << 63
#define LONG_MAX_DIGITS 19
#elif LONG_MAX < 1u << 127
#define LONG_MAX_DIGITS 39
#else
#error "unsupported LONG_MAX"
#endif

Now, you can use

wchar_t buffer[LONG_MAX_DIGITS + 2];
int len = swprintf(buffer, sizeof buffer / sizeof *buffer, L"%li", -42l);

to get a stack-allocated wide-character string. For a heap-allocated string, use wcsdup() if available or a combination of malloc() and memcpy() otherwise.

Christoph
  • 164,997
  • 36
  • 182
  • 240
1

Many people would recommend you avoid this approach, because it's not apparent that the user of your function will have to call free at some point. Usual approach is to write into a supplied buffer.

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
0

Since you receive a long, you know it's range will be in –2,147,483,648 to 2,147,483,647 and since swprintf() uses locale ("C") by default (you control that part), you only need 11 characters. This saves you from string_size_of_long().

You could either (for locale C):

wchar_t* ltostr(long value) {
     wchar_t *wchar_copy = malloc(12 * sizeof(wchar_t));
     swprintf(wchar_copy, 12, L"%li", value);
     return wchar_copy;
 }

Or more general but less portable, you could use _scwprintf to get the length of the string required (but then it's similar to your original solution).

PS: I'd simplify the memory allocation and freeing more than this "tool-box" function.

Wernight
  • 36,122
  • 25
  • 118
  • 131
  • You don't know that! `sizeof(long)` is platform-dependent. – Oliver Charlesworth Jun 08 '10 at 16:24
  • You can always use `_scwprintf` or use an optimistic approach: Try `swprintf()` and if it fails (returned value == buffer size), then double the buffer size and loop. – Wernight Jun 08 '10 at 16:27
  • @Oli: see http://stackoverflow.com/questions/2999036/whats-the-easiest-way-to-convert-a-long-in-c-to-a-char/3000378#3000378 for a way to get the correct value at compile-time – Christoph Jun 08 '10 at 19:04
0

You can use the preprocessor to calculate an upper bound on the number of chars required to hold the text form of an integer type. The following works for signed and unsigned types (eg MAX_SIZE(int)) and leaves room for the terminating \0 and possible minus sign.

#define MAX_SIZE(type) ((CHAR_BIT * sizeof(type)) / 3 + 2)
caf
  • 233,326
  • 40
  • 323
  • 462