私自身のncursesライブラリを作成していましたが、突然、snprintf()が指定した長さを超えて返されました。これは、定義された動作か私の間違いですか?snprintf()が指定された長さをオーバーフローしました
niko: snippets $ cat snprintf.c
#include <unistd.h>
#include <stdio.h>
char *example_string="This is a very long label. It was created to test alignment functions of VERTICAL and HORIZONTAL layout";
void snprintf_test(void) {
char tmp[72];
char fmt[32];
int len;
unsigned short x=20,y=30;
snprintf(fmt,sizeof(fmt),"\033[%%d;%%dH\033[0m\033[48;5;%%dm%%%ds",48);
len=snprintf(tmp,sizeof(tmp),fmt,y,x,0,example_string);
write(STDOUT_FILENO,tmp,len);
}
int main(void) {
snprintf_test();
}
niko: snippets $
今、私たちは情報をデバッグしてコンパイルして実行します:
niko: snippets $ gcc -g -o snprintf snprintf.c
niko: snippets $ gdb ./snprintf -ex "break snprintf_test" -ex run
.....
Reading symbols from ./snprintf...done.
Breakpoint 1 at 0x40058e: file snprintf.c, line 10.
Starting program: /home/deptrack/depserv/snippets/snprintf
Breakpoint 1, snprintf_test() at snprintf.c:10
10 unsigned short x=20,y=30;
Missing separate debuginfos, use: dnf debuginfo-install glibc-2.22-16.fc23.x86_64
(gdb) s
12 snprintf(fmt,sizeof(fmt),"\033[%%d;%%dH\033[0m\033[48;5;%%dm%%%ds",48);
(gdb) print sizeof(fmt)
$1 = 32
(gdb) print sizeof(tmp)
$2 = 72
(gdb) s
13 len=snprintf(tmp,sizeof(tmp),fmt,y,x,0,example_string);
(gdb) print fmt
$3 = "\033[%d;%dH\033[0m\033[48;5;%dm%48s\000\000\000\000\000"
(gdb) print example_string
$4 = 0x4006c0 "This is a very long label. It was created to test alignment functions of VERTICAL and HORIZONTAL layout"
(gdb) s
14 write(STDOUT_FILENO,tmp,len);
(gdb) print len
$5 = 124
(gdb) print sizeof(tmp)
$6 = 72
(gdb)
プログラムは、文字列の末尾にゴミを出力する(再現性)スニペットコードはこれです。ご覧のとおり、snprintf()から返された変数len
は、関数が許容サイズ72を超えて印刷したことを示しています。これはバグですか、間違いですか?この動作が定義されている場合、なぜsnprintf()docsは最大でn
文字を出力すると言いますか?非常に誤解を招きやすく、バグが発生しやすいステートメント。この問題を解決するために私自身のsnprintf()を書く必要があります。
'snprintf()'は書いた文字数を返しません。必ず、書式設定された文字列全体を印刷するのに十分な余裕があれば、書き込む数字を返します。戻り値は、最初の試行で十分に大きくなければ、バッファを作るのにどれだけの大きさがあるかを調べるのに使うことができます。 – Dmitri