Por que o parâmetro 'n' do snprintf é ignorado?

8

Eu descobri que o nparâmetro de snprintf()parece ser ignorado no meu código.

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

Isso imprime 5 quando eu esperava imprimir 2. O que está acontecendo?

Westin
fonte
A variável asdfcontém "olá" ou "h"? Se ele contiver "h", o parâmetro não será ignorado.
Nick Gammon

Respostas:

7

snprintf () não gravará mais de <size> (argumento 2d do snprintf) no seu buffer, mas conta (e descarta os caracteres extras) que teria escrito, se houvesse espaço suficiente e esse é o número que retorna . Sim, pode ser confuso!

Veja esta referência snprintf () .

JRobert
fonte
5
Seria útil porque você pode usar snprintfum buffer muito pequeno, anote o número retornado e, em seguida, mallocum buffer do tamanho apropriado e faça-o novamente. Dessa forma, você sabe quantos bytes alocar.
Nick Gammon
4
@NickGammon: Ou você não pode snprintfarmazenar nenhum buffer (um ponteiro de destino nulo é explicitamente descrito como um argumento válido para o caso destlength == 0) ao medir o comprimento.
supercat
11
De fato. Isso também é feito nas rotinas de saída de texto do Windows para medir quanto espaço algum texto em alguma fonte ocuparia, sem realmente desenhá-lo.
Nick Gammon
3

Um esboço de teste para o Arduino Uno:

char buffer[10];

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

void loop() {
}

Como o @JRobert escreveu, o "teria" é a chave. Até onde eu sei, apenas o snprintf e o vsnprintf retornam um número "teria".

Eu acho que o motivo é poder saber se a string foi truncada. Suponha que o parâmetro 'size' seja 25 e a sequência de formatação seja muito longa; o valor de retorno poderá ser testado em relação a 25. Se o valor de retorno for 26 (o número de bytes "teria"), a sequência de caracteres será truncada.
Não foi possível recuperar essas informações quando o número "teria" não estava disponível.

Mínimo
fonte
2

Para conclusão, a página de manual dos fprintfestados:

A função snprintf () deve ser equivalente a sprintf (), com a adição do argumento n, que indica o tamanho do buffer referido por s. Se n for zero, nada deve ser escrito es pode ser um ponteiro nulo. Caso contrário, os bytes de saída além do n-1 serão descartados em vez de serem gravados na matriz, e um byte nulo será gravado no final dos bytes realmente gravados na matriz.

e, mais relevante:

Após a conclusão bem-sucedida, a função snprintf () retornará o número de bytes que seriam gravados em s se n fosse suficientemente grande, excluindo o byte nulo final.

Greenonline
fonte