C 为什么printf说明符格式%n不起作用?
这是我的代码:C 为什么printf说明符格式%n不起作用?,c,printf,specifier,C,Printf,Specifier,这是我的代码: #include <stdio.h> int main(void) { int n; fprintf(stdout, "Hello%n World\n", &n); fprintf(stdout, "n: %d\n", n); return 0; } 为什么fprintf格式说明符“%n”不起作用 为什么要打印的字符串被中断 ISO/IEC 9899:201x C11-7.21.6.1-fprintf功能 转换说明符及
#include <stdio.h>
int main(void) {
int n;
fprintf(stdout, "Hello%n World\n", &n);
fprintf(stdout, "n: %d\n", n);
return 0;
}
fprintf
格式说明符“%n”
不起作用李>
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=C:/Program\ Files/mingw-w64/x86_64-8.1.0-posix-seh-rt_v6-rev
0/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/lto-wrapper.exe
Target: x86_64-w64-mingw32
Configured with: ../../../src/gcc-8.1.0/configure --host=x86_64-w64-mingw32 --bu
ild=x86_64-w64-mingw32 --target=x86_64-w64-mingw32 --prefix=/mingw64 --with-sysr
oot=/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64 --enable-shared --enable
-static --disable-multilib --enable-languages=c,c++,fortran,lto --enable-libstdc
xx-time=yes --enable-threads=posix --enable-libgomp --enable-libatomic --enable-
lto --enable-graphite --enable-checking=release --enable-fully-dynamic-string --
enable-version-specific-runtime-libs --disable-libstdcxx-pch --disable-libstdcxx
-debug --enable-bootstrap --disable-rpath --disable-win32-registry --disable-nls
--disable-werror --disable-symvers --with-gnu-as --with-gnu-ld --with-arch=noco
na --with-tune=core2 --with-libiconv --with-system-zlib --with-gmp=/c/mingw810/p
rerequisites/x86_64-w64-mingw32-static --with-mpfr=/c/mingw810/prerequisites/x86
_64-w64-mingw32-static --with-mpc=/c/mingw810/prerequisites/x86_64-w64-mingw32-s
tatic --with-isl=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-pkgv
ersion='x86_64-posix-seh-rev0, Built by MinGW-W64 project' --with-bugurl=https:/
/sourceforge.net/projects/mingw-w64 CFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x
86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x
86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/
include' CXXFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-posix-seh-rt_v6
-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include
-I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CPPFLAGS=' -I/c/
mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prere
quisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw
32-static/include' LDFLAGS='-pipe -fno-ident -L/c/mingw810/x86_64-810-posix-seh-
rt_v6-rev0/mingw64/opt/lib -L/c/mingw810/prerequisites/x86_64-zlib-static/lib -L
/c/mingw810/prerequisites/x86_64-w64-mingw32-static/lib '
Thread model: posix
gcc version 8.1.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project)
如中所述,%n
在MinGW系统上使用的Microsoft C库中默认禁用:
重要的
由于%n
格式本身就不安全,因此默认情况下会禁用它。如果在格式字符串中遇到%n
,将调用无效的参数处理程序,如参数验证中所述。要启用%n
支持,请参阅
微软声称的%n
是否真的不安全,这一点值得商榷。显示的支持此声明的示例将此printf
函数与使用可变格式字符串相结合,攻击者可通过缓冲区溢出错误更改该字符串
在某些Microsoft系统(但可能不是最新的)上,您可以通过以下方式修复程序:
#include <stdio.h>
int main(void) {
int n;
_set_printf_count_output(1);
fprintf(stdout, "Hello%n World\n", &n);
fprintf(stdout, "n: %d\n", n);
return 0;
}
输出:
Hello World
n: 5
您试图打印一个单位化的整数。由于未初始化,因此行为未定义。编译器可以自由地从代码中删除整数,然后“破坏”printf调用。“类型C、n、p和S,以及带有printf函数的C和S的行为,都是Microsoft扩展,与ANSI不兼容。”我有点困惑。甚至ANSI C也支持%n,所以它不是缺少
-std=c99
选项的情况(gcc用于默认为-std=gnu89
)。一个简单的例子表明它应该是有效的。问题中的代码与文件中的代码相同吗?我的意思是,你确定“Hello%n World\n”
字符串中没有任何奇怪的非ASCII字符吗?错误的%n字符可能是一个问题,即使它看起来与正确的字符相同。OP使用的是mingw,它使用标准库的MSVC实现(一个古老版本),因此可能只是MSVC故意不符合要求。(众所周知,MS错误地认为%n是不安全的,并禁用它作为一种强化措施。)一个可变格式字符串,攻击者可通过Microsoft在此处引发的缓冲区溢出错误更改该字符串。它破坏了可移植性。多么方便。这在Visual Studio上工作,但是如果我使用_set_printf_count_output(1);在MinGW上,我得到了一个错误:“未定义对“\uu imp\u set\u printf\u count\u output”的引用。@AlessandroAvolio:好的,无论如何这都是一个不可移植的解决方案。我将用一种更好的方法来修改答案。mingw有没有办法在不改变源代码的情况下,通过链接正确的lib文件来解决这个问题?我认为他们甚至提供了一个增强的libc,修复了所有printf错误。当然,你可以将你自己的.o文件链接到一个调用此答案中函数的ctor,但我记得他们提供了一种开箱即用的方法。。。
#include <stdio.h>
int main(void) {
int n;
n = fprintf(stdout, "Hello");
fprintf(stdout, " World\n");
fprintf(stdout, "n: %d\n", n);
return 0;
}
Hello World
n: 5