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”
    不起作用
  • 为什么要打印的字符串被中断
  • ISO/IEC 9899:201x C11-7.21.6.1-fprintf功能

    转换说明符及其含义如下:

    (…)

    %n参数应是指向有符号整数的指针,该整数中写入了到目前为止写入输出流的字符数 通过调用fprintf。未转换任何参数,但有一个参数已转换 消耗。如果转换规范包含任何标志,则会显示一个字段 宽度或精度,行为未定义

    (…)

    这是我在代码::块上使用的编译器版本:

    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