linux - Bagaimana untuk menggunakan snprintf untuk mencetak kandungan asal dan beberapa kandungan baharu ke dalam tatasusunan?
仅有的幸福
仅有的幸福 2017-05-27 17:44:46
0
1
871

snprintfFungsi 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.

仅有的幸福
仅有的幸福

membalas semua(1)
洪涛

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()的第二个参数代表的是缓冲区的大小,在这里应该是LENGTHsizeof(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 calling sprintf(), snprintf(), vsprintf(), and vsnprintf(). Depending on the version of gcc(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 buf Walau bagaimanapun, piawaian menyatakan secara jelas bahawa keputusan tidak ditentukan jika penimbal sumber dan destinasi bertindih apabila memanggil sprintf(), snprintf() , vsprintf() dan vsnprintf() Bergantung pada versi gcc(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 keluarga printf() ini akan tidak ditentukan. 🎜
🎜Jadi bagaimana anda "mencetak kandungan asal anda dan beberapa kandungan baharu ke dalam tatasusunan"? Satu cara ialah menetapkan penimbal yang dihantar kepada 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
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan