Каково использование %n
спецификатор формата в C? Кто-либо мог объяснить с примером?
Ничего не напечатано. Аргумент должен быть указателем на знаковое 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
в реальном мире, но я помню, что он использовался в старых школьных уязвимостях 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 в истинное значение.
Да, это эзотерическое использование, но всегда полезно знать при написании демона, чтобы избежать дыр в безопасности? :D
.Аргумент, связанный с% n, будет рассматриваться как int * и заполнен общим количеством символов, напечатанных в этой точке в printf.
Из здесь мы видим, что он хранит количество символов, напечатанных на данный момент.
n
Аргументом является указатель на целое число, в которое записывается количество байт, выведенных на данный момент этим вызовом одной из функцийfprintf()
. Никакой аргумент не преобразуется.
Пример использования:
int n_chars = 0;
printf("Hello, World%n", &n_chars);
n_chars
будет иметь значение 12
.
Пока что все ответы касаются того, что % n
делает, но не того, почему это вообще может кому-то понадобиться. Я считаю, что это несколько полезно с sprintf
/ snprintf
, когда вам может понадобиться позже разбить или изменить результирующую строку, поскольку сохраненное значение является индексом массива в результирующей строке. Однако это приложение намного полезнее с sscanf
, тем более что функции из семейства scanf
возвращают не количество обработанных символов, а количество полей.
Еще одно действительно хакерское использование - это получение бесплатного псевдо-журнала10 одновременно с выводом числа в рамках другой операции.
Он ничего не печатает. Он используется для определения количества символов, выведенных до появления %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;
}