views:

149

answers:

6

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.

+3  A: 

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.

JSBangs
Downvoters, why?
JSBangs
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).
Khnle
Note that `wcsdup` et al are not ANSI compliant (AFAIK).
Oli Charlesworth
@Khnle, it doesn't leak so long as the caller frees the returned string. I thought that was too basic to point out.
JSBangs
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
@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.
Khnle
@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.
JSBangs
@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
@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.
Khnle
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
nice solution, still one issue left: the string returned is longer than the actual 'value', simple cropping will do it.
dh82
@dh82, the string returned is not longer than the actual value. Think about what `strdup` does to determine what to allocate.
JSBangs
ah indeed, didnt check that :)
dh82
+3  A: 
int charsRequired = snprintf(NULL, 0, "%ld", value) + 1;
char *long_str_buffer = malloc(charsRequired);
snprintf(long_str_buffer, charsRequired, "%ld", value);
Matthew Flaschen
+1  A: 

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.

Oli Charlesworth
A: 

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
You don't know that! `sizeof(long)` is platform-dependent.
Oli Charlesworth
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
@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
+2  A: 

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
superbe, thats something I was looking for. thx
dh82
A: 

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