C中%n格式说明符的用法是什么?
C中%n
格式说明符的用法是什么? 任何人都可以解释一个例子吗?
没有打印。 参数必须是一个指向一个有符号的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
variables中),但到目前为止,还没有人真正给出过使用它的例子。 这里是一个:
int n; printf("%s: %nFoo\n", "hello", &n); printf("%*sBar\n", n, "");
将打印:
hello: Foo Bar
与Foo和酒吧alignment。 (在这个特殊的例子中,如果不使用%n
,这样做是微不足道的,总的来说,总是可以打破第一个printf
调用:
int n = printf("%s: ", "hello"); printf("Foo\n"); printf("%*sBar\n", n, "");
是否稍微增加的便利是值得使用像%n
这样深奥的东西(可能会引入错误),这是值得商榷的。)
从这里我们看到它存储了迄今为止打印的字符数。
参数应该是一个指向一个整数的指针,在这个整数中写入到
fprintf()
函数之一中写入到输出的字节数。 没有参数被转换。
一个示例用法是:
int n_chars = 0; printf("Hello, World%n", &n_chars);
那么n_chars
的值将是12
。
我还没有真正看到%n
说明符在实际应用中的实际用途,但是我记得它在一段时间之前就被格式化string攻击用在了老式的printf漏洞中。
有些事情是这样的
void authorizeUser( char * username, char * password){ ...code here setting authorized to false... printf(username); if ( authorized ) { giveControl(username); } }
恶意用户可以利用传递给printf的username参数作为格式string,并使用%d
, %c
或w / e的组合来遍历调用堆栈,然后将授权variables修改为真值。
是的这是一个深奥的使用,但总是有用的知道什么时候编写一个守护进程,以避免安全漏洞? :d
与%n相关的参数将被视为一个int *,并填充printf中当前打印的总字符数。
到目前为止,所有答案都是关于%n
,但不是为什么有人会首先想要它。 我发现这对于sprintf
/ snprintf
来说可能有些用处,因为以后可能需要分解或修改结果string,因为存储的值是数组索引到结果string中。 然而,使用sscanf
这个应用程序是非常有用的,特别是因为scanf
系列中的函数不会返回已处理的字符数,而是返回字段数。
另一个非常蹩脚的用法是在打印一个数字的同时免费获得一个伪log10作为另一个操作的一部分。
它不打印任何东西。 它用于计算在格式string中出现%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
很好地解决了我的问题的情况。 不像我以前的回答 ,在这种情况下,我不能想出一个好的select。
我有一个GUI控件,显示一些指定的文本。 这个控件可以以粗体(或斜体或下划线等)显示该文本的一部分,并且可以通过指定起始和结束字符索引来指定哪个部分。
在我的情况下,我正在用snprintf
生成文本到控件,我希望其中一个replace为粗体。 find这个替代的开始和结束指数是不平凡的,因为:
-
该string包含多个replace,其中一个replace是用户指定的任意文本。 这意味着对我关心的replace进行文本search可能是不明确的。
-
格式string可能是本地化的,它可能使用位置格式说明符
$
POSIX扩展名。 因此,search格式说明符的原始格式string本身并不重要。 -
本地化方面也意味着我不能容易地将格式string拆分成多个对
snprintf
调用。
因此,find围绕某个特定替代指标的最直接的方法是做:
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);
它将存储printf()
函数中迄今为止打印的字符数。
例:
int a; printf("Hello World %n \n", &a); printf("Characters printed so far = %d",a);
这个程序的输出将是
Hello World Characters printed so far = 12
%n是C99,不适用于VC ++。