Почему формат спецификатора printf% n не работает? - PullRequest
0 голосов
/ 02 марта 2019

Это мой код:

#include <stdio.h>

int main(void) {
    int n;

    fprintf(stdout, "Hello%n World\n", &n);
    fprintf(stdout, "n: %d\n", n);

    return 0;
} 

Это мой вывод:

Hellon: 0
  1. Почему не работает спецификатор формата fprintf "%n"?
  2. Почему печатная строка прерывается?

ISO / IEC 9899: 201x C11 - 7.21.6.1 - Функция fprintf

Спецификаторы преобразования и их значения:

(...)

% n Аргумент должен быть указателем на целое число со знаком, в которое записывается количество символов, записанных в выходной поток до настоящего времени посредством этого вызова fprintf.Ни один аргумент не преобразуется, но один используется.Если спецификация преобразования включает какие-либо флаги, ширину поля или точность, поведение не определено....

(...)

Это версия моего компилятора, используемая в Code :: Blocks:

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)

1 Ответ

0 голосов
/ 02 марта 2019

Как указано в документации Microsoft , %n по умолчанию отключено в библиотеке Microsoft C, используемой в вашей системе MinGW:

Важно

Поскольку формат %n изначально небезопасен, по умолчанию он отключен.Если в строке формата встречается %n, вызывается недопустимый обработчик параметра, как описано в разделе «Проверка параметров».Чтобы включить поддержку %n, см. _set_printf_count_output.

Вопрос о том, является ли %n на самом деле небезопасным, как заявляет Microsoft, вызывает большие сомнения.Примеры, показанные в поддержку этого утверждения, объединяют эту функцию 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;
} 

Для более портативного подхода здесь есть обходной путь, чтобы избежать использования %n и при этом получить те же результаты:

#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
...