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