Determining sprintf buffer size - what's the standard?

前端 未结 7 1836
臣服心动
臣服心动 2020-11-28 06:51

When converting an int like so:

char a[256];
sprintf(a, \"%d\", 132);

what\'s the best way to determine how large a should be? I a

相关标签:
7条回答
  • 2020-11-28 07:22

    If you're printing a simple integer, and nothing else, there's a much simpler way to determine output buffer size. At least computationally simpler, the code is a little obtuse:

    char *text;
    text = malloc(val ? (int)log10((double)abs(val)) + (val < 0) + 2 : 2);
    

    log10(value) returns the number of digits (minus one) required to store a positive nonzero value in base 10. It goes a little off the rails for numbers less than one, so we specify abs(), and code special logic for zero (the ternary operator, test ? truecase : falsecase). Add one for the space to store the sign of a negative number (val < 0), one to make up the difference from log10, and another one for the null terminator (for a grand total of 2), and you've just calculated the exact amount of storage space required for a given number, without calling snprintf() or equivalents twice to get the job done. Plus it uses less memory, generally, than the INT_MAX will require.

    If you need to print a lot of numbers very quickly, though, do bother allocating the INT_MAX buffer and then printing to that repeatedly instead. Less memory thrashing is better.

    Also note that you may not actually need the (double) as opposed to a (float). I didn't bother checking. Casting back and forth like that may also be a problem. YMMV on all that. Works great for me, though.

    0 讨论(0)
  • 2020-11-28 07:28

    Its good that you are worried about buffer size. To apply that thought in code, I would use snprintf

    snprintf( a, 256, "%d", 132 );
    

    or

    snprintf( a, sizeof( a ), "%d", 132 );  // when a is array, not pointer
    
    0 讨论(0)
  • 2020-11-28 07:29

    First off, sprintf is the devil. If anything, use snprintf, or else you risk trashing memory and crashing your app.

    As for the buffer size, it's like all other buffers - as small as possible, as big as necessary. In your case, you have a signed integer, so take the largest possible size, and feel free to add a little bit of safety padding. There is no "standard size".

    It's also not dependent on what system you're running on. If you define the buffer on the stack (like in your example), it depends on the size of the stack. If you created the thread yourself, then you determined the stack size yourself, so you know the limits. If you are going to expect recursion or a deep stack trace, then you need to extra careful as well.

    0 讨论(0)
  • 2020-11-28 07:42

    The max possible number of bits in an int is CHAR_BIT * sizeof(int), and a decimal digit is "worth" at least 3 bits, so a loose upper bound on the space required for an arbitrary int is (CHAR_BIT * sizeof(int) / 3) + 3. That +3 is one for the fact that we rounded down when dividing, one for the sign, one for the nul terminator.

    If by "on a 32 bit system" you mean that you know int is 32 bits, then you need 12 bytes. 10 for the digits, one for the sign, one for the nul terminator.

    In your specific case, where the int to be converted is 132, you need 4 bytes. Badum, tish.

    Where fixed-size buffers can be used with a reasonable bound, they are the simpler option. I not-so-humbly submit that the bound above is reasonable (13 bytes instead of 12 for 32 bit int, and 23 bytes instead of 21 for 64 bit int). But for difficult cases, in C99 you could just call snprintf to get the size, then malloc that much. That's overkill for such a simple case as this.

    0 讨论(0)
  • 2020-11-28 07:43

    It's possible to make Daniel Standage's solution work for any number of arguments by using vsnprintf which is in C++11/C99.

    int bufferSize(const char* format, ...) {
        va_list args;
        va_start(args, format);
        int result = vsnprintf(NULL, 0, format, args);
        va_end(args);
        return result + 1; // safe byte for \0
    }
    

    As specified in c99 standard, section 7.19.6.12 :

    The vsnprintf function returns the number of characters that would have been written had n been sufficiently large, not counting the terminating null character, or a negative value if an encoding error occurred.

    0 讨论(0)
  • 2020-11-28 07:43

    I see this conversation is a couple of years old, but I found it while trying to find an answer for MS VC++ where snprintf cannot be used to find the size. I'll post the answer I finally found in case it helps anyone else:

    VC++ has the function _scprintf specifically to find the number of characters needed.

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