Какая польза в %формат N описатель в C?

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

10 ответов


ничего не печатал. Аргумент должен быть указателем на подписанный 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

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


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

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

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

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

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

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

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


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

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

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

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

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


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


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

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


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

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

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

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

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

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


он будет хранить значение количества символов, напечатанных до сих пор в этом


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