Что такое использование спецификатора формата %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
, и я хотел бы, чтобы одна из замен была сделана смелой. Найти начальный и конечный индексы для этой подстановки нетривиально, потому что:
строка содержит несколько подстановок, и одна из подстановок является произвольным, заданным пользователем текстом. Это означает, что выполнение текстового поиска замены, о которой я забочусь, потенциально неоднозначно.
строка формата может быть локализована, и она может использовать элемент
$
расширение 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; }