Mengapa parameter 'n' dari snprintf diabaikan?

8

Saya telah menemukan bahwa nparameter snprintf()sepertinya diabaikan dalam kode saya.

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

Ini mencetak 5 ketika saya harapkan mencetak 2. Apa yang terjadi?

Westin
sumber
Apakah variabel tersebut asdfberisi "halo" atau "h"? Jika mengandung "h" maka parameter belum diabaikan.
Nick Gammon

Jawaban:

7

snprintf () tidak akan menulis lebih dari <size> (argumen 2d snprintf) ke buffer Anda, tetapi itu menghitung (dan membuang tambahan) karakter yang akan ditulisnya, seandainya ada cukup ruang, dan itu adalah jumlah yang dikembalikan . Ya, itu bisa membingungkan!

Lihat referensi snprintf () ini .

JRobert
sumber
5
Akan sangat membantu karena Anda bisa snprintfke buffer yang sangat kecil, perhatikan nomor yang dikembalikan, kemudian mallocbuffer dengan ukuran yang sesuai, dan lakukan lagi. Dengan begitu Anda tahu berapa byte yang dialokasikan.
Nick Gammon
4
@NickGammon: Atau Anda bisa snprintftanpa buffer apa pun (pointer tujuan nol secara eksplisit dijelaskan sebagai argumen yang valid untuk destlength == 0 case) saat mengukur panjang.
supercat
1
Memang. Itu juga dilakukan dalam rutinitas keluaran teks Windows untuk mengukur seberapa banyak ruang yang akan ditempati teks dalam beberapa font, tanpa benar-benar menggambarnya.
Nick Gammon
3

Sketsa tes untuk Arduino Uno:

char buffer[10];

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

void loop() {
}

Seperti @JRobert menulis, "akan memiliki" adalah kuncinya. Sejauh yang saya tahu hanya snprintf dan vsnprintf mengembalikan angka "akan".

Saya pikir alasannya adalah untuk dapat mengetahui apakah string itu terpotong. Misalkan parameter 'size' adalah 25 dan string format sangat panjang, maka nilai kembali dapat diuji terhadap 25. Jika nilai kembali adalah 26 ("akan memiliki" jumlah byte), maka string terpotong.
Informasi ini tidak dapat diambil ketika nomor "akan" tidak tersedia.

Mencatat
sumber
2

Untuk selesai, halaman manual untuk fprintfstatus:

Fungsi snprintf () harus sama dengan sprintf (), dengan tambahan argumen n yang menyatakan ukuran buffer yang dirujuk oleh s. Jika n adalah nol, tidak ada yang ditulis dan s dapat menjadi pointer nol. Jika tidak, byte keluaran di luar n-1 harus dibuang alih-alih ditulis ke array, dan byte nol ditulis di akhir byte yang sebenarnya ditulis ke dalam array.

dan, lebih relevan:

Setelah berhasil diselesaikan, fungsi snprintf () akan mengembalikan jumlah byte yang akan ditulis ke s jika n cukup besar tidak termasuk terminasi null byte.

Greenonline
sumber