Каково использование спецификатора формата %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;
}
		Ответ 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С++.