Какая польза от спецификатора формата% n в C? - PullRequest
114 голосов
/ 04 августа 2010

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

Ответы [ 10 ]

175 голосов
/ 04 августа 2010

Большинство из этих ответов объясняют, что %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 (и, возможно, с ошибками), открыт для обсуждения.)

139 голосов
/ 04 августа 2010

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

#include <stdio.h>

int main()
{
  int val;

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

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

  return 0;

}

Предыдущий код выводит:

17 голосов
/ 04 августа 2010

Я на самом деле не видел много практических применений спецификатора %n в реальном мире, но я помню, что он использовался в уязвимостях oldschool 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

13 голосов
/ 04 августа 2010

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

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

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

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

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

9 голосов
/ 04 августа 2010

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

8 голосов
/ 04 августа 2010

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

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

6 голосов
/ 10 августа 2015

На днях я оказался в ситуации, когда %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);
1 голос
/ 19 февраля 2013

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

Пример:

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

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

Hello World
Characters printed so far = 12
1 голос
/ 04 августа 2010

Ничего не печатается.Он используется, чтобы выяснить, сколько символов было напечатано до того, как %n появилось в строке формата, и вывести его в предоставленное целое число:

#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)

0 голосов
/ 05 августа 2010

% n - это C99, работает не с VC ++.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...