Зачем добавлять 1 или 2 ко второму аргументу snprintf? - PullRequest
0 голосов
/ 18 июля 2011

Какова роль 1 и 2 в этих функциях snprintf?Может ли кто-нибудь объяснить это

snprintf(argv[arg++], strlen(pbase) + 2 + strlen("ivlpp"), "%s%ccivlpp", pbase, sep);
snprintf(argv[arg++], strlen(defines_path) + 1, "-F\"%s\"", defines_path);

Ответы [ 3 ]

3 голосов
/ 18 июля 2011

Роль +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.

2 голосов
/ 18 июля 2011

Программист, чей код вы читаете, не знает, как правильно использовать snprintf.Второй аргумент - это размер буфера , поэтому он почти всегда должен выглядеть следующим образом:

snprintf(buf, sizeof buf, "..." ...);

Выше приведено для ситуаций, когда buf является массивом, а не указателем.В последнем случае вы должны передать размер буфера:

snprintf(buf, bufsize, "...", ...);

Вычисление размера буфера не требуется.

Кстати, поскольку вы пометили вопрос как связанный с qt.Есть очень хороший класс QString, который вы должны использовать вместо этого.

0 голосов
/ 18 июля 2011

На первый взгляд оба кажутся неправильными.

  1. В первом случае правильное вычисление будет path + sep + name + NUL, поэтому 2 будет казаться нормальным, но для имени, которое использует вызов strlenilvpp при использовании кода форматирования вместо cilvpp, что на один символ длиннее.

  2. Во втором случае число добавляемых символов равно 4 (-L""), поэтому числодобавить должно быть 5 из-за окончания NUL.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...