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

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

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

Это печатает 5, хотя я ожидал, что будет напечатано 2. Что происходит?

, 👍8

Обсуждение

Содержит ли переменная asdf «привет» или «h»? Если он содержит «h», то параметр не был проигнорирован., @Nick Gammon


3 ответа


Лучший ответ:

7

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

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

,

Это было бы полезно, потому что вы могли бы snprintf обратиться к очень маленькому буферу, записать возвращаемое число, затем malloc буфер соответствующего размера и сделать это снова. Таким образом, вы знаете, сколько байт нужно выделить., @Nick Gammon

@NickGammon: Или вы можете snprintf вообще не использовать буфер (нулевой указатель назначения явно описан как действительный аргумент для случая destlength==0) при измерении длины., @supercat

Действительно. Это также делается в процедурах вывода текста Windows, чтобы измерить, сколько места будет занимать текст определенного шрифта, без его фактического рисования., @Nick Gammon


2

Тестовый скетч для 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 возвращает число, которое "будет иметь".

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

,

2

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

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

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

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

,