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 做了什么( 打印任何内容,并将迄今为止打印的字符数写入到一个intvariables中),但到目前为止,还没有人真正给出过使用它的例子。 这里是一个:

 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 ++。