Question

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.

Was it helpful?

Solution

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.

OTHER TIPS

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.

int charsRequired = snprintf(NULL, 0, "%ld", value) + 1;
char *long_str_buffer = malloc(charsRequired);
snprintf(long_str_buffer, charsRequired, "%ld", value);

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.

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.

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)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top