Почему параметр 'n' в snprintf игнорируется?

8

Я обнаружил, что в моем коде nпараметр snprintf()игнорируется.

char asdf[10];
Serial1.println(snprintf(asdf, 2, "hello"));

Это печатает 5, когда я ожидал бы это напечатать 2. Что происходит?

Westin
источник
Переменная asdfсодержит "привет" или "ч"? Если он содержит «h», то параметр не был проигнорирован.
Ник Гэммон

Ответы:

7

snprintf () не будет записывать в ваш буфер больше чем <size> (2d аргумент snprintf), но он подсчитывает (и отбрасывает лишние) символы, которые он написал бы, если бы было достаточно места, и это число, которое он возвращает , Да, это может сбить с толку!

Смотрите эту ссылку snprintf () .

JRobert
источник
5
Это было бы полезно, потому что вы могли snprintfбы использовать очень маленький буфер, записать возвращаемое число, затем mallocбуфер соответствующего размера и сделать это снова. Таким образом, вы знаете, сколько байтов выделить.
Ник Гэммон
4
@NickGammon: Или вы можете snprintfвообще не буферизовать (нулевой указатель назначения явно описывается как действительный аргумент для случая destlength == 0) при измерении длины.
суперкат
1
Верно. Это также делается в подпрограммах вывода текста Windows, чтобы измерить, сколько места занимал бы какой-либо текст в каком-либо шрифте, фактически не рисуя его.
Ник Гэммон
3

Тестовый скетч для Arduino Uno:

char buffer[10];

void setup() {
  Serial.begin(9600);
  int n = snprintf(buffer, 2, "hello");
  Serial.println(n);
  Serial.println(buffer);
}

void loop() {
}

Как писал @JRobert, ключом «будет иметь». Насколько я знаю, только snprintf и vsnprintf возвращают "бы иметь" номер.

Я думаю, причина в том, чтобы быть в состоянии сказать, была ли строка обрезана. Предположим, что параметр 'size' равен 25, а строка формата очень длинная, тогда возвращаемое значение можно сравнить с 25. Если возвращаемое значение было 26 (число "будет иметь" байтов), то строка была усечена.
Эту информацию было невозможно получить, когда номер «хотел бы» был недоступен.

йота
источник
2

Для завершения, справочная страница для fprintfсостояний:

Функция snprintf () должна быть эквивалентна sprintf () с добавлением аргумента n, который устанавливает размер буфера, на который ссылается s. Если n равно нулю, ничего не должно быть записано, а s может быть нулевым указателем. В противном случае выходные байты за пределами n-1 должны быть отброшены вместо записи в массив, а нулевой байт записывается в конце байтов, фактически записанных в массив.

и, более актуально:

После успешного завершения функция snprintf () должна вернуть количество байтов, которые были бы записаны в s, если бы n было достаточно большим, за исключением завершающего нулевого байта.

Greenonline
источник