Hacker News new | past | comments | ask | show | jobs | submit login

asprintf. It's so much easier to write

    asprintf(s, "%s.pid", progname);
than

    s = malloc(strlen(progname) + 5);
    strcpy(s, progname);
    strcat(s, ".pid");
and it avoids errors in buffer-size computation too.

(Unfortunately asprintf isn't C99; but you can construct it easily out of vsnprintf: http://code.google.com/p/libcperciva/source/browse/trunk/uti...)




I've done something similar to your vsnprintf()-based code by using snprintf() into an undersized buffer, realloc()ing the buffer to the returned value, then calling snprintf() again. This works well for reused buffers that have a length associated with them and may need to grow over time, but clearly vsnprintf() could do the same thing.


asprintf is very expensive; one tends to use snprintf all over the place in ones code.

Not disagreeing with you; asprintf is a good thing to have around.


Oh, I wouldn't use asprintf in any performance-critical code. But I wouldn't be using character strings in any performance-critical code either, so that issue doesn't arise for me.


It's a shame they didn't offer msprintf(), which would use malloc(), and asprintf(), which would use alloca(), for cases where you only want a temporary string without heap usage/fragmentation overhead.


You can't use alloca from inside a library function, since it would allocate within the library function's stack frame and the allocation would no longer be valid when the function returned. (Or rather, you can use alloca within library functions, but you can't return a pointer to that allocation, so it wouldn't be useful here.)

Theoretically you could define an alloca()ed-pointer-returning Xsprintf as a macro, though... (but ask tptacek notes, it's probably a bad idea).


Something like this (C99; given p, stack-allocates p_sasprintf_buf of size at most 16 if the string would fit, and uses asprintf otherwise):

    #include <err.h>
    #include <stdio.h>
    #include <stdlib.h>
 
    #define SASPRINTF_MAXLEN 16
    #define SASPRINTF_MERGE(a, b) a ## b
    #define SASPRINTF_LEN(p) SASPRINTF_MERGE(p, _sasprintf_len)
    #define SASPRINTF_BUF(p) SASPRINTF_MERGE(p, _sasprintf_buf)
    #define SASPRINTF(p, fmt, ...) \
        size_t  SASPRINTF_LEN(p) = snprintf(NULL, 0, (fmt), __VA_ARGS__); \
        char    SASPRINTF_BUF(p)[SASPRINTF_LEN(p) <= SASPRINTF_MAXLEN ? SASPRINTF_LEN(p) + 1 : 0]; \
        if (SASPRINTF_LEN(p) <= SASPRINTF_MAXLEN) { \
            snprintf(SASPRINTF_BUF(p), SASPRINTF_LEN(p) + 1, (fmt), __VA_ARGS__); \
            p = SASPRINTF_BUF(p); \
        } else { \
            if (asprintf(&p, (fmt), __VA_ARGS__) == -1) \
                err(1, "SASPRINTF_L at %s, %d", __FILE__, __LINE__); \
        }
    #define SASPRINTF_FREE(p) do { \
            if (p != SASPRINTF_BUF(p)) \
                free(p); \
        } while(0)
 
    /* Test harness */
    int main(void);
 
    int main(void) {
            char *p, *p2;
    
            SASPRINTF(p, "%s", "foo");
            SASPRINTF(p2, "%s", "Really long string, really.");
 
            printf("%s\n%s\n", p, p2);
 
            SASPRINTF_FREE(p);
            SASPRINTF_FREE(p2);
 
            exit(EXIT_SUCCESS);
    }
I was going to say "...but you have to be pretty insane to do this", but I haven't managed to get incorrect-but-compiling code out of the above macros. Of course, I'm not at all convinced that it's faster than asprintf... (even after the obvious optimizations.)


This is not valid C99. In C99, arrays must have at least one element. Also, what is err.h? Whatever it is, it is not C99.

As for speed, if asprintf() does something clever to avoid rendering the string twice, this is actually slower unless snprintf() is faster than a malloc() call (unlikely). Furthermore, some compilers implement variable-length arrays with malloc() so for these, this is definitely not an improvement.

Beyond the speed of this particular call, using variable-length arrays can have a performance hit in general since gcc is unable to inline functions using them.


That's a good point - I can see why they wouldn't exactly want to encourage macro hacks at this point.


Using alloca() with unbounded string lengths is terribly unsafe, which defeats the purpose of the idiom.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: