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


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

10 105

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, и я хотел бы, чтобы одна из замен была сделана смелой. Найти начальный и конечный индексы для этой подстановки нетривиально, потому что:

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

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