How to improve buffer size determination for printfing various integer types?

后端 未结 4 1117
萌比男神i
萌比男神i 2021-01-21 09:36

When converting an integer to text, typically I create a big buffer to use with sprintf() to hold any potential result.

char BigBuffer[50];         


        
相关标签:
4条回答
  • 2021-01-21 10:12

    These are fine.

    I designed the original snprintf() function (in *BSD, that eventually made it into C99) to return the number of characters that would have been printed, had the buffer been large enough. If you have a conforming snprintf() you can do the printing twice, with the first telling you how much space to allocate (you must add one for the terminating '\0' of course). This has two obvious drawbacks: it has to do the formatting twice, and it introduces the possibility of synchronization issues, where the first call changes something (e.g., writing via %n directive) so that the second call produces different output.

    Unfortunately, there are non-compliant snprintf() implementations where this does not work anyway. [Edit: it works for the usage in jxh's answer, where you supply a large buffer; the failing case is when you supply a too-small buffer to find out how much room you need.]

    0 讨论(0)
  • 2021-01-21 10:17

    It looks good to me. You've rounded the decimal up, added an extra character for the negative sign and the null, and one extra for good measure. I don't think you need to worry about numbers coming out longer if you're not using features from <locale.h>.

    My question is about what you intend to do with these. Are you simply constructing them on the stack, or are you putting lots of them into memory?

    With temporary arrays on the stack, you normally wouldn't fuss over a few bytes as it's unlikely to affect cache performance. It certainly isn't going to blow out your memory.

    If you are planning to store lots of these, you may want to consider pooling. However, you would need to consider the memory overhead of pooling. The very nature of a pool means you reserve more memory than you are going to use. And if compiling 64-bit, your pointers are 8 bytes. If most of your numbers are 4 characters long, then the 8-byte pointer plus the 5 bytes of storage for each number would negate any possible benefits, except perhaps for 64-bit numbers.

    These are just my thought processes. It seems to me that you have trimmed the fat nicely. I tend to be a little more conservative, but that may be mostly paranoia. Keeping it simple is usually the way to go, and over-thinking can be a trap. If you are over-thinking then consider the reasons why, and decide whether it's a problem that actually requires that much thought.

    0 讨论(0)
  • 2021-01-21 10:25

    asprintf() is handy, it takes a char ** and uses malloc() to get the needed space so you need to free() it later.

    No need to worry about how much space you need.

    int asprintf(char **ret, const char *format, ...); 
    
    char *p
    asprintf(&p, "%XXXX", ...); 
    :
    :
    free(p);
    
    0 讨论(0)
  • 2021-01-21 10:25

    Here's a scheme, expanding my earlier comment. You use the INTMAX_DECIMAL_BUFN as your worst case buffer size, and use it for printing with snprintf(). The value returned by snprintf() is used to declare a VLA that matches exactly the array size needed for the printed string, and that string is copied to the VLA.

    #define INTMAX_DECIMAL_BUFN ((size_t) (sizeof(intmax_t)*CHAR_BIT*0.302) + 3)
    
    char numstr[INTMAX_DECIMAL_BUFN];
    
    int main () {
        int n = snprintf(numstr, sizeof(numstr), "%hu", USHRT_MAX);
        char usbuffer[n+1];
        strcpy(usbuffer, numstr);
        printf("Size:%zu Len:%zu %s\n", sizeof(usbuffer), strlen(usbuffer), usbuffer);
    }
    

    If thread safety is an issue, the numstr variable could be made thread local (with C.11's _Thread_local, or some compiler specific extension similar to GCC's __thread).

    The value of this solution depends on whether the savings in stack space is worth the extra compute to perform the strcpy(). If most of your numbers using the larger integer types actually take on values much smaller than the max, then this technique could provide you with significant savings (depending on how many arrays you are creating).

    0 讨论(0)
提交回复
热议问题