C中%n
格式说明符的用法是什么?有人可以用一个例子来解释吗?
答案 0 :(得分:173)
这些答案中的大多数都解释了%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
那样深奥的东西(可能会引入错误),这是值得商榷的。)
答案 1 :(得分:138)
什么都没打印。参数必须是指向signed 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 :(得分:17)
我还没有真正看到%n
说明符的许多实际实际使用情况,但我记得它在oldschool printf漏洞中使用了format 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
答案 3 :(得分:13)
从here我们看到它存储了到目前为止打印的字符数。
n
参数应该是一个指向整数的指针,该整数写入到目前为止通过调用fprintf()
函数之一写入输出的字节数。没有参数被转换。
示例用法是:
int n_chars = 0;
printf("Hello, World%n", &n_chars);
n_chars
的值为12
。
答案 4 :(得分:9)
与%n关联的参数将被视为int *,并填充printf中该点打印的总字符数。
答案 5 :(得分:8)
到目前为止,所有答案都与%n
的答案有关,但不是为什么有人会首先想要它。我发现它对sprintf
/ snprintf
有些用处,因为您可能需要稍后分解或修改结果字符串,因为存储的值是结果字符串中的数组索引。但是,对于sscanf
,此应用程序更有用,特别是因为scanf
系列中的函数不返回已处理的字符数而是字段数。
另一个真正的hackish用法是在打印数字作为另一个操作的一部分的同时免费获得伪log10。
答案 6 :(得分:5)
有一天,我发现自己处于%n
很好地解决我的问题的情况。与my earlier answer不同,在这种情况下,我无法设计出一个好的替代方案。
我有一个显示一些指定文本的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);
答案 7 :(得分:1)
它不会打印任何内容。它用于计算在%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;
}
答案 8 :(得分:1)
它将存储到目前为止printf()
函数中打印的字符数的值。
示例:
int a;
printf("Hello World %n \n", &a);
printf("Characters printed so far = %d",a);
该程序的输出将是
Hello World
Characters printed so far = 12
答案 9 :(得分:0)
那些想使用%n格式说明符的人可能想看看这个:
请勿使用"%n"
格式字符串说明符
摘要
粗心使用"%n"
格式的字符串可能会导致漏洞。
说明
滥用格式字符串可能导致多种漏洞。其中大多数内容在其他地方都有介绍,但是本文档介绍了一种特定类型的格式字符串漏洞,这对于格式字符串是完全唯一的。公开文件对这些漏洞的覆盖范围不一致。
在C中,在printf()和sprintf()类型函数中使用“%n”格式规范可以更改内存值。这些格式的设计/实现不当可能导致内存内容更改而产生漏洞。许多格式漏洞,尤其是带有指定符而不是“%n”的格式漏洞,会导致传统的失败,例如分段错误。 “%n”说明符产生了更多的破坏性漏洞。 “%n”漏洞可能会带来次要影响,因为它们也可能会成为计算和网络资源的主要消耗者,因为可能必须转移大量数据来生成利用该漏洞所需的指针值。
避免使用"%n"
格式说明符。使用其他方式来实现您的目的。
来源:link
答案 10 :(得分:-6)
%n是C99,不适用于VC ++。