145

%nCでのフォーマット指定子の使用は何ですか? 誰かが例で説明できますか?

4

11 に答える 11

212

これらの回答のほとんどは何をするのか(何も印刷%n ず、これまでに印刷された文字数を変数に書き込むこと)を説明していますが、これまでのところ、それがどのように使用intされているかの例を実際に示した人は誰もいません。これが1つです:

int n;
printf("%s: %nFoo\n", "hello", &n);
printf("%*sBar\n", n, "");

印刷されます:

hello: Foo
       Bar

FooとBarを揃えます。(この特定の例を使用せずにそれを行うのは簡単%nであり、一般に、最初のprintf呼び出しを常に分割することができます:

int n = printf("%s: ", "hello");
printf("Foo\n");
printf("%*sBar\n", n, "");

わずかに追加された利便性が、%n(そしておそらくエラーを導入する)ような難解なものを使用する価値があるかどうかは議論の余地があります。)

于 2010-08-04T03:43:04.817 に答える
162

何も印刷されません。引数は、これまでに書き込まれた文字数が格納されているsignedintへのポインタである必要があります。

#include <stdio.h>

int main()
{
  int val;

  printf("blah %n blah\n", &val);

  printf("val = %d\n", val);

  return 0;

}

前のコードは次のように出力します。

blah  blah
val = 5
于 2010-08-03T22:14:42.103 に答える
19

指定子が実際に実際に使用されている例はあまり見たことがありませんが、かなり前にフォーマット文字列攻撃による%n古い学校の printf 脆弱性で使用されたことを覚えています。

このようになったもの

void authorizeUser( char * username, char * password){

    ...code here setting authorized to false...
    printf(username);

    if ( authorized ) {
         giveControl(username);
    }
}

悪意のあるユーザーは、ユーザー名パラメーターがフォーマット文字列として printf に渡されることを利用して%d%cまたは w/e の組み合わせを使用してコール スタックを調べ、認証された変数を真の値に変更する可能性があります。

ええ、これは難解な使い方ですが、セキュリティ ホールを回避するためにデーモンを作成するときに知っておくと便利ですか? :D

于 2010-08-03T22:37:34.810 に答える
14

ここから、これまでに印刷された文字数が格納されていることがわかります。

n 引数は、関数の1つへのこの呼び出しによってこれまでに出力に書き込まれたバイト数が書き込まれる整数へのポインタでなければなりませんfprintf()。引数は変換されません。

使用例は次のとおりです。

int n_chars = 0;
printf("Hello, World%n", &n_chars);

n_charsその場合、値は。になり12ます。

于 2010-08-03T22:17:01.997 に答える
13

に関連付けられた引数%nはとして扱われ、のint*その時点で印刷された合計文字数で埋められprintfます。

于 2010-08-03T22:15:13.117 に答える
13

これまでのところ、すべての答えはそれについてです%nが、そもそもなぜ誰もがそれを望んでいるのかというわけではありません。格納されている値は結果の文字列への配列インデックスであるため、後で結果の文字列を分割または変更する必要がある場合は、sprintf/を使用すると便利です。ただし、このアプリケーションは、特にファミリ内の関数が処理された文字数ではなくフィールド数を返すためsnprintf、はるかに便利です。sscanfscanf

もう1つの本当にハックな使用法は、別の操作の一部として数値を出力すると同時に、疑似log10を無料で取得することです。

于 2010-08-04T12:16:04.960 に答える
12

先日、私は自分%nの問題をうまく解決できる状況にいることに気づきました。以前の回答とは異なり、この場合、適切な代替案を考案することはできません。

指定したテキストを表示する GUI コントロールがあります。このコントロールは、そのテキストの一部を太字 (または斜体、下線など) で表示できます。また、開始文字インデックスと終了文字インデックスを指定して、その部分を指定できます。

私の場合、コントロールへのテキストを で生成していますがsnprintf、置換の 1 つを太字にしたいと考えています。この置換の開始インデックスと終了インデックスを見つけることは、次の理由から簡単ではありません。

  • 文字列には複数の置換が含まれており、置換の 1 つは任意のユーザー指定のテキストです。これは、気になる置換をテキストで検索すると、あいまいになる可能性があることを意味します。

  • フォーマット文字列はローカライズされている可能性があり、$位置フォーマット指定子に POSIX 拡張を使用している可能性があります。したがって、フォーマット指定子自体の元のフォーマット文字列を検索することは簡単ではありません。

  • ローカリゼーションの側面は、フォーマット文字列を複数の への呼び出しに簡単に分割できないことも意味しますsnprintf

したがって、特定の置換の周りのインデックスを見つける最も簡単な方法は、次のようにすることです。

char buf[256];
int start;
int end;

snprintf(buf, sizeof buf,
         "blah blah %s %f yada yada %n%s%n yakety yak",
         someUserSpecifiedString,
         someFloat,
         &start, boldString, &end);
control->set_text(buf);
control->set_bold(start, end);
于 2015-08-10T10:42:31.813 に答える
2

何も印刷されません。%nこれは、フォーマット文字列に表示される前に印刷された文字数を把握し、それを提供されたintに出力するために使用されます。

#include <stdio.h>

int main(int argc, char* argv[])
{
    int resultOfNSpecifier = 0;
    _set_printf_count_output(1); /* Required in visual studio */
    printf("Some format string%n\n", &resultOfNSpecifier);
    printf("Count of chars before the %%n: %d\n", resultOfNSpecifier);
    return 0;
}

のドキュメント_set_printf_count_output

于 2010-08-03T22:23:09.543 に答える
1

その関数でこれまでに印刷された文字数の値を格納しprintf()ます。

例:

int a;
printf("Hello World %n \n", &a);
printf("Characters printed so far = %d",a);

このプログラムの出力は次のようになります。

Hello World
Characters printed so far = 12
于 2013-02-19T04:08:22.220 に答える
-6

%n は C99 です。VC++ では動作しません。

于 2010-08-04T22:33:25.280 に答える