Каково использование спецификатора формата% n в C?

Каково использование спецификатора формата %n в C? Может ли кто-нибудь объяснить пример?

Ответ 1

Ничего не напечатано. Аргумент должен быть указателем на подписанный int, где сохраняется количество символов, записанных до сих пор.

#include <stdio.h>

int main()
{
  int val;

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

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

  return 0;

}

Предыдущий код печатает:

blah  blah
val = 5

Ответ 2

В большинстве этих ответов объясняется, что делает %n (то есть ничего не печатать и писать количество символов, напечатанных до сих пор, переменной int), но пока никто не привел пример того, как использовать в нем есть. Вот один из них:

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 (и, возможно, введения ошибок), открыто для обсуждения.)

Ответ 3

Я действительно не видел много практического использования в реальном мире спецификатора %n, но я помню, что он использовался в уязвимостях oldschool printf с форматом string attack довольно долго назад.

Что-то вроде этого

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

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

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

где злоумышленник может воспользоваться параметром username, который передается в printf как строка формата, и использовать комбинацию %d, %c или w/e для прохождения стека вызовов, а затем изменять разрешенную переменную к истинному значению.

Да, это эзотерическое использование, но всегда полезно знать при написании демона, чтобы избежать дыр в безопасности?: D

Ответ 4

Из здесь мы видим, что в нем хранится количество напечатанных символов.

n Аргумент должен быть указателем на целое число, в которое записано количество байтов, записанных на выходе до сих пор этим вызовом одной из функций fprintf(). Аргумент не преобразуется.

Пример использования:

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

n_chars будет иметь значение 12.

Ответ 5

Аргумент, связанный с% n, будет обрабатываться как int * и заполнен числом общих символов, напечатанным в этой точке printf.

Ответ 6

Пока что все ответы о том, что делает %n, но не о том, почему кто-то хотел бы этого в первую очередь. Я нахожу это несколько полезным с sprintf/snprintf, когда вам может понадобиться позже разбить или изменить результирующую строку, так как сохраненное значение является индексом массива в результирующей строке. Однако это приложение намного более полезно с sscanf, тем более что функции в семействе scanf возвращают не количество обработанных символов, а количество полей.

Еще одно по-настоящему хакерское использование - это бесплатное получение псевдожурнала 10 одновременно с печатью числа как части другой операции.

Ответ 7

На днях я оказался в ситуации, когда %n красиво решит мою проблему. В отличие от моего более раннего ответа, в этом случае я не могу разработать хорошую альтернативу.

У меня есть элемент управления графическим интерфейсом, который отображает определенный текст. Этот элемент управления может отображать часть этого текста жирным шрифтом (или курсивом, или подчеркнутым и т.д.), И я могу указать, какую часть указывать начальные и конечные индексы символов.

В моем случае я создаю текст для элемента управления с помощью snprintf, и я хочу, чтобы одна из подстановок была выделена жирным шрифтом. Поиск начальных и конечных индексов для этой подстановки является нетривиальным, потому что:

  • Строка содержит несколько подстановок, а одна из подстановок - произвольный, заданный пользователем текст. Это означает, что выполнение текстового поиска замещения, о которой я забочусь, потенциально неоднозначно.

  • Строка формата может быть локализована, и она может использовать расширение $ 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);

Ответ 8

Он ничего не печатает. Он используется, чтобы выяснить, сколько символов было напечатано до того, как %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)

Ответ 9

Он сохранит значение количества символов, напечатанных до сих пор в этой функции printf().

Пример:

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

Выход этой программы будет

Hello World
Characters printed so far = 12

Ответ 10

% n - C99, работает не с VС++.