1

I have a question about the following code:

void testing(int idNumber)
{
    char name[20];

    snprintf(name, sizeof(name), "number_%d", idNumber);
}

The size of the char array name is 20, so if the idNumber is 111 it works, but how about the actual idNumber is 111111111111111111111111111111, how to determine how big the char array should be in order to keep the result of snprintf?

4
  • It's easy enough to calculate the size required for any numeric type: 2^(sizeof(type) * 8) is the maximum (unsigned) value of the type. a one byte type (char or short) allows for a 3 digit number, 2 bytes 5 (the minimal size of an int), 8, 10, 13, and so on (so the interval is 2 or 3 chars). Add the sign char and room for a terminating \0 char, and sizeof(type) * 3 + 2 should do the trick. If you are processing doubles and floats, add room for a decimal point, too Commented Oct 22, 2014 at 14:35
  • @Elias Van Ootegem Note: processing double with "%f" could need a buffer of size 1 + DBL_MAX_10_EXP + 1 + 1 + 6 +1 for the sign, DBL_MAX digits, ., fraction and '\0'. At least 47 and maybe 318 char as on my platform. Your suggested formula works well for integers. Commented Oct 22, 2014 at 14:42
  • @chux: indeed... I'd like to see the length required on a system where the long double is implemented as a quadrupal precision type (128 bit) Commented Oct 22, 2014 at 14:51
  • @Elias Van Ootegem long double uses one B.A.Buffer. ;-) (Maybe 4942 char) Commented Oct 22, 2014 at 14:57

5 Answers 5

3

Well, if int is 32 bits on your platform, then the widest value it could print would be -2 billion, which is 11 characters, so you'd need 7 for number_, 11 for %d, and 1 for the null terminator, so 19 total.

But you should check the return value from snprintf() generally, to make sure you had enough space. For example, if the "locale" is set to other than the standard "C" one, it could print thousands separators, in which case you'd need 2 more characters than you have.

Sign up to request clarification or add additional context in comments.

Comments

2

There is only one good answer:
Ask snprintf itself (Pass a length of 0).

It returns the size of the output it would have written if the buffer was big enough, excluding the terminating 0.

man-page for snprintf

Standard-quote (C99+Amendments):

7.21.6.5 The snprintf function

Synopsis

#include <stdio.h>
int snprintf(char * restrict s, size_t n,
const char * restrict format, ...);

Description
2 The snprintf function is equivalent to fprintf, except that the output is written into an array (specified by argument s) rather than to a stream. If n is zero, nothing is written, and s may be a null pointer. Otherwise, output characters beyond the n-1st are discarded rather than being written to the array, and a null character is written at the end of the characters actually written into the array. If copying takes place between objects that overlap, the behavior is undefined.
Returns
3 The snprintf 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. Thus, the null-terminated output has been completely written if and only if the returned value is nonnegative and less than n.

2 Comments

Something like char name[snprintf(name, 0, "number_%d", idNumber) + 1]; snprintf(name, sizeof(name), "number_%d", idNumber);?
or even snprintf(NULL, 0, "format", extra, arguments)
2

Look at the documentation of snprintf. If you pass NULL for the destination and 0 for the size, it will return the number of bytes needed. So you do that first, malloc the memory, and do another snprintf with the right size.

All the printf functions return the number of bytes printed (excluding a trailing zero), except snprintf will return the number of characters that would have been printed if the length was unlimited.

Comments

1

Quote from here:

If the resulting string would be longer than n-1 characters, the remaining characters are discarded and not stored, but counted for the value returned by the function.

Comments

1

To use a right-sized buffer, calculate its maximum needs.

#define INT_PRINT_SIZE(i) ((sizeof(i) * CHAR_BIT)/3 + 3)

void testing(int idNumber) {
  const char format[] = "number_%d";
  char name[sizeof format + INT_PRINT_SIZE(idNumber)];
  snprintf(name, sizeof(name), format, idNumber);
}

This approach assumes C locale. A more robust solution could use

  ...
  int cnt = snprintf(name, sizeof(name), format, idNumber);
  if (cnt < 0 || cnt >= sizeof(name)) Handle_EncodingError_SurprisingLocale().

Akin to https://stackoverflow.com/a/26497268/2410359

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.