7

最近、確認したい奇妙なケースに気付きました。

SUS により%n、フォーマット文字列の for は、int出力に書き込まれるバイト数にそれぞれ設定されます。さらに、 forsnprintf(dest, 3, "abcd")destを指し"ab\0"ます。なんで?n (n = 3) バイト以下が出力 (destバッファー) に書き込まれるためです。

私はコードのためにそれを推測しました:

int written;
char dest[3];
snprintf(dest, 3, "abcde%n", &written);

written2 に設定されます (null 終了はカウントから除外されます)。しかし、GCC 4.8.1 を使用して作成したテストでは、written5 に設定されていました。標準を誤解していましたか? バグですか?未定義の動作ですか?

編集:

@wildplasser 氏は次のように述べています。

... フォーマット文字列の %n の動作は、未定義または実装定義の可能性があります ...

... 実装では、完全なフォーマット文字列 (%n を含む) の処理を​​シミュレートする必要があります ...

@パーは言った:

writtenが検出された時点で書き込まれる文字数が 5 であるためです%n。これは正しい動作です。 末尾の null を引いた文字snprintfまでのみコピーします ...size

と:

これを見る別の方法は、最大 2 文字しか処理されなかった場合でも遭遇しなかったであろうということです。そのため、無効な値を持つことが%n予想されます...written

と:

... 文字列全体がprintf()ルールによって処理され、次にmax-length が適用されます ...

それが標準、標準草案、または何らかの公式ソースであることを確認できますか?

4

2 に答える 2

7

writtenが検出された時点で書き込まれる文字数が 5 であるためです%n。これは正しい動作です。 snprintf末尾のヌルを引いた文字までのみコピーしsizeます(したがって、あなたの場合は 3-1 == 2 です。文字列の書式設定動作を書き込みのみの文字から分離する必要があります。

別の見方をすると、最大 2 文字しか処理されなかった場合は に遭遇することすらなかったため、無効な値を持つことが%n予想される可能性があります。その時点でwritten有効な何かが検出されると予想していた場合(検出されなかった場合)、そこにバグが発生します。written%n

したがって、文字列全体がprintf()ルールによって処理され、次にmax-length が適用されることを覚えておいてください。

于 2014-08-28T19:12:20.423 に答える
5

それはバグではありません: ISOC99 は言います

snprintf 関数は fprintf と同等です [...] n-1 番目を超える出力文字は、配列に書き込まれるのではなく破棄されます [...]

したがって、後続の出力を破棄するだけですが、それ以外は同じように動作します。

于 2014-08-28T19:15:01.477 に答える