Rumah > Soal Jawab > teks badan
snprintf
Fungsi ini memerlukan panjang yang ditentukan, dan pengkompil akan melakukan semakan di luar sempadan, jadi ia mesti dipastikan bahawa panjang sasaran lebih panjang daripada jumlah semua parameter. Tetapi pertimbangkan prosedur berikut:
#include <stdio.h>
#include <string.h>
#define LENGTH 1024
int main() {
char cache[LENGTH];
memset(cache, 0, LENGTH);
snprintf(cache, sizeof(LENGTH), "%s/ruaruarua", cache);
return 0;
}
Selepas membuka program ini-Wall
, ralat akan dilaporkan:
test.c: In function ‘main’:
test.c:9:44: error: ‘/ruaruarua’ directive output truncated writing 10 bytes into a region of size 4 [-Werror=format-truncation=]
snprintf(cache, sizeof(LENGTH), "%s/ruaruarua", cache);
~~~~^~~~~~
test.c:9:5: note: ‘snprintf’ output 11 or more bytes into a destination of size 4
snprintf(cache, sizeof(LENGTH), "%s/ruaruarua", cache);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors
Ralat ini dijangka kerana memang boleh melepasi garisan. Jadi persoalannya, bagaimana saya boleh melengkapkan fungsi yang sama tanpa melaporkan ralat?
Sayagcc
版本比较新,7.1.1
, dianggarkan versi lama pengkompil tidak akan melaporkan ralat ini.
PHP中文网2017-05-27 17:46:46
Pertama sekali, parameter kedua snprintf()
mewakili saiz penimbal, di sini ia sepatutnya LENGTH
, sizeof(LENGTH)
Nilainya ialah 4
(Saya rasa apa yang anda mahu tulis ialah sizeof(cache)
). Jadi, adakah ia OK selepas menukarnya kepada snprintf(cache, LENGTH, "%s/ruaruarua", cache);
? Mari lihat contoh ini: snprintf()
的第二个参数代表的是缓冲区的大小,在这里应该是LENGTH
,sizeof(LENGTH)
的值是4
(我猜你想写的应该是sizeof(cache)
吧)。那么,改成snprintf(cache, LENGTH, "%s/ruaruarua", cache);
之后就行了吗?我们看看这个例子:
#include <stdio.h>
int main()
{
char buf[20] = "hello";
snprintf(buf, 20, "%s world", buf);
puts(buf);
return 0;
}
这个例子企图给buf
末尾添加一个字符串,看看输出
world
并没有达到期望的结果。这是为什么呢?snprintf()
的手册里有这么一段:
Some programs imprudently rely on code such as the following
sprintf(buf, "%s some further text", buf);
to append text to
buf
. However, the standards explicitly note that the results are undefined if source and destination buffers overlap when callingsprintf()
,snprintf()
,vsprintf()
, andvsnprintf()
. Depending on the version ofgcc(1)
used, and the compiler options employed, calls such as the above will not produce the expected results.即如果原始和目标缓冲区重叠的话,这些
printf()
家族的函数执行结果将是未定义的。
那该如何如何“向一个数组中打印自己原有的内容和一些新的内容”呢?一种方式是把传给snprintf()
的缓冲区设为数组中字符串的末尾:
snprintf(buf + strlen(buf), 20, " world");
那如何连续往缓冲区末尾添加数据呢?注意到printf()
#include <stdio.h>
#include <string.h>
int main()
{
char buf[40];
char *p = buf;
p += sprintf(p, "hello %s\n", "world");
p += sprintf(p, "hello %s", "again");
/* and more similar calls... */
puts(buf);
return 0;
}
Contoh ini cuba menambah rentetan pada penghujung buf
, lihat pada output
hello world
hello again
Tidak mencapai hasil yang diinginkan. kenapa ni? Terdapat perenggan ini dalam manual snprintf()
: 🎜
🎜Sesetengah program secara tidak berhemat bergantung pada kod seperti berikut🎜 rrreee 🎜untuk menambah teks pada🎜Jadi bagaimana anda "mencetak kandungan asal anda dan beberapa kandungan baharu ke dalam tatasusunan"? Satu cara ialah menetapkan penimbal yang dihantar kepadabuf
Walau bagaimanapun, piawaian menyatakan secara jelas bahawa keputusan tidak ditentukan jika penimbal sumber dan destinasi bertindih apabila memanggilsprintf()
,snprintf()
,vsprintf()
danvsnprintf()
Bergantung pada versigcc(1)
yang digunakan dan pilihan pengkompil bekerja, panggilan seperti di atas tidak akan menghasilkan hasil yang diharapkan.🎜 🎜Iaitu, jika penimbal asal dan sasaran bertindih, hasil pelaksanaan fungsi keluargaprintf()
ini akan tidak ditentukan. 🎜
snprintf()
ke hujung rentetan dalam tatasusunan: 🎜
rrreee
🎜Kemudian bagaimana untuk menambah data secara berterusan ke penghujung penimbal? Perhatikan bahawa fungsi mengembalikan nilai keluarga printf()
ialah bilangan aksara yang dicetak (bilangan aksara yang dicetak), maka anda boleh memanggilnya seperti ini: 🎜
rrreee
🎜Hasilnya ialah 🎜
rrreee