Это часть Могу я ответить на свой вопрос? . Дополнительные ответы приветствуются.
Как обнаружить snprintf
ошибки в C?
Используйте более широкое значение size_t
или unsigned
cast.
if ((size_t) snprintf(... ) >= sizeof buf) {
error();
}
или педантично
int length_needed = snprintf(... );
if (length_needed < 0 || (unsigned) length_needed >= sizeof buf) {
error();
}
Тестирование на усечение
Иногда очень важно обнаружить усеченную строку из snprintf()
.
char buf[13];
char *command = "format_drive";
char *sub_command = "cancel";
snprintf(buf, sizeof buf, "%s %s", command, sub_command);
system(buf); // system("format_drive") leads to bye-bye data
Код ОК
Один тест, если возвращаемое значение соответствует или превышает размер массива назначения, равен почти .
char buf[20];
if (snprintf(buf, sizeof buf, "Random int %d", rand()) >= sizeof buf) {
fprintf(stderr, "Buffer too small");
exit(EXIT_FAILURE);
}
Отрицательное значение
Функция snprintf
возвращает количество символов, которое было бы записано, если бы n
было достаточно большим, не считая завершающий нулевой символ, или отрицательное значение, если произошла ошибка кодирования. Таким образом, вывод с нулевым символом завершается полностью, если и только если возвращаемое значение неотрицательно и меньше n
. C11dr §7.21.6.5 3
Надежный код будет напрямую проверять наличие отрицательного значения для редкой ошибки кодирования . if (some_int <= some_size_t)
, к сожалению, недостаточно, поскольку int
будет преобразовано в size_t
. int
отрицательное возвращаемое значение становится большим положительным size_t
. Это обычно намного больше, чем размер массива, но не указывается таковым.
// Pedantic check for negative values
int length_needed = snprintf(... as above ...);
if (length_needed < 0 || length_needed >= sizeof buf) {
fprintf(stderr, "Buffer too small");
exit(EXIT_FAILURE);
}
Знак несоответствия
Некоторые предупреждения компилятора скуливают о сравнении целых чисел различной значимости, таких как gcc's -Wsign-compare
с int
и size_t
. Приведение к size_t
кажется разумным.
предупреждение: сравнение между целочисленными выражениями со знаком и без знака [-Wsign-compare]
// Quiet different sign-ness warnings
int length_needed = snprintf(... as above ...);
if (length_needed < 0 || (size_t) length_needed >= sizeof buf) {
fprintf(stderr, "Buffer too small");
exit(EXIT_FAILURE);
}
Pedantic
C не указывает, что положительные значения int
являются поддиапазоном size_t
. size_t
может быть unsigned short
, а затем SIZE_MAX < INT_MAX
. (Я не знаю такой реализации.) Таким образом, приведение к (size_t) some_int
может изменить значение. Вместо этого приведение положительного возвращаемого значения к unsigned
(INT_MAX <= UINT_MAX
всегда истинно) не изменит значение и обеспечит сравнение с самым широким типом без знака между unsigned
и size_t
.
// Quiet different sign-ness warnings
int length_needed = snprintf(... as above ...);
if (length_needed < 0 || (unsigned) length_needed >= sizeof buf) {
fprintf(stderr, "Buffer too small");
exit(EXIT_FAILURE);
}