Является ли 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, который не является стандартным поведением.
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-1st являются отбрасывается, а не записывается в массив, и нулевой символ записывается в конце символов, фактически записанных в массив. Если копирование происходит между объектами, которые перекрываются, поведение не определено.
возвращает
3 Thesnprintfфункция возвращает количество символов, которые были бы написаны имелnбыл достаточно большим, не считая завершающего нулевого символа или отрицательного значения, если произошла ошибка кодирования. Таким образом, вывод с нулевым завершением был полностью записан тогда и только тогда, когда возвращаемое значение неотрицательно и меньшеn.С одной стороны наказание
иначе выходные символы за пределами
n-1st отбрасываются вместо того, чтобы быть написанным в массив, и нулевой символ записывается в конце символов, фактически написанных в массивеговорит, что
если (sуказывает на массив длиной 3 символа, и)n- 3, то будут записаны 2 символа, а символы за пределами 2-го будут отброшены; тогда нулевой символ пишется после этих 2 (и нулевой символ будет 3-й символ, написанный).и это, я считаю, отвечает на первоначальный вопрос.
ОТВЕТ:
Если копирование происходит между объектами, которые перекрываются, поведение не определено.
Еслиn0, то ничего не записывается в выходной
в противном случае, если ошибки кодирования не обнаружены,вывод всегда заканчивается нулем (независимо от того, помещается ли выход в выходной массив или нет; если нет, то некоторые символы отбрасываются такой, что выходной массив никогда не переполняется),
в противном случае (при обнаружении ошибок кодирования) вывод может остаться не-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