Является ли snprintf () всегда нулевым завершением?



всегда ли snprintf null завершает буфер назначения?



другими словами, достаточно ли этого:



char dst[10];

snprintf(dst, sizeof (dst), "blah %s", somestr);


или вы должны сделать так, если somestr достаточно долго?



char dst[10];

somestr[sizeof (dst) - 1] = '';
snprintf(dst, sizeof (dst) - 1, "blah %s", somestr);


меня интересует как то, что говорит стандарт, так и то, что может сделать какой-то популярный libc, который не является стандартным поведением.

645   5  

5 ответов:

как другие ответы устанавливают: это должны:

snprintf ... Записывает результаты в буфер символьной строки. (...) завершается нулевым символом, если buf_size не равен нулю.

поэтому все, что вам нужно позаботиться, это то, что вы не передаете ему буфер нулевого размера, потому что (очевидно) он не может записать ноль в "никуда".


, будьте осторожны это Microsoft библиотека нет функции snprintf но вместо исторически только была функция с именем _snprintf (обратите внимание на символ подчеркивания), который не добавлять завершающий нуль. Вот документы (VS 2012, ~ ~ VS 2013):

http://msdn.microsoft.com/en-us/library/2ts7cx93%28v=vs.110%29.aspx

Возвращаемое Значение

пусть len-длина отформатированного строка данных (не включая завершающий нуль). len и count находятся в байтах для _snprintf, широкий символы _snwprintf.

  • если LEN

  • если len = count, то символы len хранятся в буфере,нет null-terminator добавляется, и LEN возвращается.

  • если LEN > подсчет, затем подсчет символов хранятся в буфере,нет null-terminator добавляется, и возвращается отрицательное значение.

(...)

Visual Studio 2015 (VC14) видимо ввел соответствующий snprintf функция, но унаследованная с ведущим подчеркиванием и номера поведение с нулевым завершением все еще существует:

The snprintf

согласно snprintf (3) manpage.

функции snprintf() и vsnprintf() пишите не более size байт (включая конечный нулевой байт ('\0')) до str.

Итак, да, нет необходимости завершать, если размер >= 1.

в соответствии со стандартом C, если размер буфера не равен 0,vsnprintf() и snprintf() null завершает вывод.

The

некоторые старые версии SunOS делали странные вещи с snprintf и, возможно, не завершали вывод и не возвращали значения, которые не соответствовали тому, что делали все остальные, но все, что было выпущено за последние 10 лет, делало то, что говорит C99.

неоднозначность начинается с самого стандарта C. Оба C99 и C11 имеют одинаковое описание . Вот описание от C99:

7.19.6.5 в snprintf функции
справка
1 #include <stdio.h> int snprintf(char * restrict s, size_t n, const char * restrict format, ...);
описание
2 The эквивалентно fprintf, за исключением того, что вывод записывается в массив (задается аргументом s), а не поток. Если n равно нулю, ничего не написано, и s может быть нулевым указателем. В противном случае выводите символы за пределы n-1 st являются отбрасывается, а не записывается в массив, и нулевой символ записывается в конце символов, фактически записанных в массив. Если копирование происходит между объектами, которые перекрываются, поведение не определено.
возвращает
3 The snprintf функция возвращает количество символов, которые были бы написаны имел n был достаточно большим, не считая завершающего нулевого символа или отрицательного значения, если произошла ошибка кодирования. Таким образом, вывод с нулевым завершением был полностью записан тогда и только тогда, когда возвращаемое значение неотрицательно и меньше n.

С одной стороны наказание

иначе выходные символы за пределами n-1 st отбрасываются вместо того, чтобы быть написанным в массив, и нулевой символ записывается в конце символов, фактически написанных в массиве

говорит, что
если (s указывает на массив длиной 3 символа, и)n - 3, то будут записаны 2 символа, а символы за пределами 2-го будут отброшены; тогда нулевой символ пишется после этих 2 (и нулевой символ будет 3-й символ, написанный).

и это, я считаю, отвечает на первоначальный вопрос.
ОТВЕТ:
Если копирование происходит между объектами, которые перекрываются, поведение не определено.
Если n 0, то ничего не записывается в выходной
в противном случае, если ошибки кодирования не обнаружены,вывод всегда заканчивается нулем (независимо от того, помещается ли выход в выходной массив или нет; если нет, то некоторые символы отбрасываются такой, что выходной массив никогда не переполняется),
в противном случае (при обнаружении ошибок кодирования) вывод может остаться не-null-завершенной.

С другой стороны
Последнее предложение

таким образом, вывод с нулевым завершением был полностью записан тогда и только тогда, когда возвращаемое значение неотрицательно и меньше n

дает неопределенность (или мой английский не очень хорошо достаточно.) Я могу интерпретировать это предложение по крайней мере двумя способами:
1. На выходе получается null-terminated если и только если возвращаемое значение неотрицательно и меньше n (что означает, что если возвращаемое значение не меньше n, т. е. выход (включая завершающий нулевой символ) не помещается в массив, тогда выход не null-завершенной).
2. На выходе получается полное (нет символы были отброшены) если и только если возвращаемое значение неотрицательно и меньше n.


я считаю, что интерпретация 1 выше противоречит ответу, вызывает непонимание и длительные дискуссии. Вот почему последнее предложение, описывающее snprintf функция нуждается в изменении, чтобы устранить любую двусмысленность (что дает основания для написания предложения к стандарту языка C).
Пример недвусмысленной формулировки Я считаю, что может быть взят изhttp://en.cppreference.com/w/c/io/fprintf (см. 4)), спасибо @ "Martin Ba" за ссылку.

Смотрите также вопрос"snprintf: существуют ли какие-либо C стандартные предложения/планы по изменению описания этой функции?".

Comments

    Ничего не найдено.