Роль +2
состоит в том, чтобы допустить нулевой терминал и внедренный символ из формата %c
, , поэтому для форматирования первой строки достаточно места для правильного форматирования. , но(как указывает 6502 ), фактически предоставленная строка на один пробел короче, чем необходимо, поскольку strlen("ivlpp")
не соответствует civlpp
в самом формате.Это означает, что последний символ (второй 'p') будет усечен в выходных данных.
Роль +1
также заставляет snprintf()
усекать отформатированные данные.Строка формата содержит 4 литеральных символа, и вам нужно разрешить нулевой терминал, поэтому код должен выделять strlen(defines)+5
.На самом деле snprintf()
усекает данные, оставляя 4 символа.
Я сомневаюсь, действительно ли код работает надежно ... распределение памяти не показано, но должно быть довольносложный - или ему придется перераспределить, чтобы избежать опасности переполнения буфера.
Поскольку комментарий от OP говорит:
Я неНе известно использование snprintf()
int snprintf(char *restrict s, size_t n, const char *restrict format, ...);
Функция snprintf()
форматирует данные как printf()
, но записывает их в строку (s
в названии) а не в файл.Первый n
в имени указывает, что функции сообщается точная длина строки, и snprintf()
гарантирует, что выходные данные обнуляются (если длина не равна 0).Он сообщает, как долго должна была быть строка;если сообщаемое значение длиннее указанного значения, вы знаете, что данные были усечены.
Таким образом, в целом snprintf()
является относительно безопасным способом форматирования строк при условии, что вы используете его правильно.Примеры, приведенные в вопросе, не демонстрируют «правильное использование».
Одно замечание: если вы работаете в MS Windows, помните, что реализация MSVC snprintf()
точно не следуетстандарт C99 (и выглядит немного так, как будто MS больше не предоставляет snprintf()
вообще; только различные альтернативы, такие как _snprintf()
).Я забыл точное отклонение, но я думаю, что это означает, что строка не заканчивается должным образом нулем в любых обстоятельствах, когда она должна быть длиннее, чем предоставленное пространство.
Для локально определенных массивов вы обычно используете:
nbytes = snprintf(buffer, sizeof(buffer), "format...", ...);
С динамически выделяемой памятью вы обычно используете:
nbytes = snprintf(dynbuffer, dynbuffsize, "format...", ...);
В обоих случаях вы проверяете, содержит ли nbytes
неотрицательное значение меньше аргумента размера;если это так, ваши данные в порядке;если значение равно или больше, ваши данные обрезаются (и вы знаете, сколько места вам нужно было выделить).
Стандарт C99 гласит:
Функция snprintfвозвращает количество символов, которое было бы записано, если бы n
было достаточно большим, не считая завершающий нулевой символ, или отрицательное значение, если произошла ошибка кодирования.Таким образом, вывод с нулевым символом в конце был полностью записан тогда и только тогда, когда возвращаемое значение неотрицательно и меньше n
.