printf

Поделись знанием:
Перейти к: навигация, поиск

printf (от англ. print formatted, «печать форматированная») — обобщённое название семейства функций или методов стандартных или широко известных коммерческих библиотек, или встроенных операторов некоторых языков программирования, используемых для форматного вывода — вывода в различные потоки значений разных типов, отформатированных согласно заданному шаблону. Этот шаблон определяется составленной по специальным правилам строкой (форматной строкой).

Наиболее ярким представителем этого семейства является функция printf, а также ряд других функций с производными от printf названиями в стандартной библиотеке языка Си (являющейся также частью стандартной библиотеки Си++ и Objective-C).

В операционных системах семейства UNIX имеется также утилита printf, служащая тем же целям форматного вывода.

Ранним прототипом такой функции можно считать оператор FORMAT языка Фортран. Функция вывода, управляемая строкой, появилась в предшественниках языка Си (BCPL и Би). В спецификации стандартной библиотеки языка Си она получила свой наиболее известный вид (с флагами, шириной, точностью и размером). Синтаксис строки шаблона вывода (называемой иногда строкой форматирования, строкой формата или форматной строкой) в дальнейшем начал использоваться и другими языками программирования (с вариациями ради приспособления к особенностям этих языков). Как правило, соответствующие функции этих языков также носят название printf и/или производные от него.

Некоторые более поздние среды программирования (например .Net) также используют концепцию вывода, управляемого форматной строкой, но с иным синтаксисом.





Содержание

История

Появление

Уже Фортран I имел операторы, обеспечивавшие форматный вывод. Синтаксис операторов WRITE и PRINT предусматривал метку, отсылающую к неисполняемому оператору FORMAT, который содержал форматную спецификацию. Спецификаторы были частью синтаксиса оператора, и компилятор сразу мог сформировать код, непосредственно выполняющий форматирование данных, что обеспечивало наилучшую производительность на вычислительных машинах тех времён. Однако имелись следующие недостатки:

  • Усложнение без того запутанного синтаксиса языка.
  • Форматную спецификацию невозможно было сформировать в ходе исполнения программы.
  • Форматная спецификация была текстуально отделена от оператора вывода, что было неудобно для сопровождения программ.

Первый прототип будущей функции printf появляется в языке BCPL в 1960-х. Функция WRITEF принимает строку форматирования, в которой тип данных указывается отдельно от самих данных в строковой переменной (тип указывался без полей флагов, ширины, точности и размера, но уже предварялся символом процента %).[1] Основной целью появления строки форматирования была передача типов аргументов (в языках программирования со статической типизацией определение типа переданного аргумента для функции с нефиксированным списком формальных параметров требует сложного и неэффективного для общего случая механизма передачи информации о типах). Сама функция WRITEF была средством упрощения вывода: вместо набора функций WRCH (вывод символа), WRITES (вывод строки), WRITEN, WRITED, WRITEOCT, WRITEHEX (вывод чисел в различной форме) использовался единый вызов, в котором можно было чередовать «просто текст» с выходными значениями.

Появившийся вслед за ним в 1969 году язык Би уже использовал название printf с простейшей строкой форматирования (аналогичной BCPL), указывался только один из трёх возможных типов и два представления числа: десятичные (%d), восьмеричные (%o), строки (%s) и символы (%c), а единственной возможностью по форматированию вывода в этих функциях было добавление символов до и после вывода значения переменной.[2]

Си и производные

С момента появления первого варианта языка Си (1970) семейство printf стало основным средством форматного вывода. Затраты на разбор форматной строки при каждом вызове функции были сочтены приемлемыми, и альтернативные вызовы для каждого типа в отдельности в библиотеку введены не были. Спецификация функции вошла в оба существующих стандарта языка, вышедших в 1990 и 1999 годах. Спецификация 1999 года содержит некоторые нововведения по отношению к спецификации 1990 года.

Язык Си++ использует стандартную библиотеку Си (в соответствии со стандартом 1990 года), в том числе и всё семейство printf.

В качестве альтернативы стандартная библиотека Си++ предложила набор классов потокового ввода и вывода. Операторы вывода этой библиотеки типобезопасны и не требуют разбора форматных строк при каждом вызове. Тем не менее, многие программисты продолжают пользоваться семейством printf, так как запись последовательности вывода с ними обычно оказывается компактнее, а суть применяемого формата — яснее.

Objective-C является довольно «тонкой» надстройкой над Си, и программы на нём могут напрямую пользоваться функциями семейства printf.

Использование в других языках программирования

Помимо Си и его производных (Си++, Objective-C), printf-подобный синтаксис строки форматирования используют многие другие языки программирования:

  • Perl — sprintf[3];
  • Python — форматирующий оператор %[4] и функция str.format;
  • PHP — функция printf[5];
  • Java — функция java.io.PrintStream.printf[6];
  • Ruby — функция printf[7];
  • Lua — функция string.format[8];
  • TCL — функция format[9];
  • GNU Octave — функция printf[10];
  • Maple — функция printf (встроенный язык)[11];
  • AMPL[12];
  • Elisp (format string &rest objects)[13];
  • OCaml — функция printf[14];
  • Haskell — функция printf[15].
  • Rust — макрос println![16]

Помимо этого, благодаря наличию утилиты printf в составе большинства UNIX-подобных систем, printf используется во многих shell-скриптах (для sh, bash, csh, zsh и т. д.).

Последователи

Некоторые более поздние языки и среды программирования также используют концепцию вывода управляемого форматной строкой, но с иным синтаксисом.

Например, в основной библиотеке классов (FCL) среды .Net имеется семейство методов System.String.Format, System.Console.Write и System.Console.WriteLine, некоторые перегрузки которых выполняют вывод своих данных в соответствии с форматной строкой. Так как в среде исполнения .Net доступна полная информация о типах объектов, необходимости передавать эту информацию в форматной строке нет.

Именование функций семейства

Все функции имеют в имени основу printf. Префиксы перед именем функции означают:

  • v (vprintf, vsnprintf и т. д.) — функция вместо переменного числа параметров принимает список аргументов va list.
  • f (fprintf, vfprintf) — вывод результата в передаваемый через параметр функции поток, вместо стандартного вывода.
  • s (sprintf, snprintf, vsprintf, vspnprintf) — запись результата в строку (буфер в памяти), а не поток.
  • n (snprintf, vnsprintf) — наличие параметра, ограничивающего максимальное количество символов для записи результата (используется только вместе с префиксом s). В Maple функция nprintf аналогична sprintf, но возвращает не текстовую строку, а имя.
  • w, перед остальными префиксами (wsprintf, wvsprintf, wnsprintf, wvnsprintf) — использующийся фирмой Microsoft префикс для реализаций семейства функций sprintf в операционных системах Windows.
  • w, после остальных префиксов (fwprintf, swprintf, wprintf) — функция использует многобайтовую кодировку (wchar_t) вместо обычных строк. (при этом функция swprintf не имеет префикса «n», хотя и принимает параметр, ограничивающий размер результирующей строки).
  • a (asprintf, vasprintf) — расширения GNU; функции аналогичные sprintf/vsprintf, но выделяющие достаточный объём памяти с помощью malloc для форматированной строки. Вместо указателя на строку эти функции принимают указатель на указатель на строку, освобождение памяти производит вызвавшая функция.

Общие соглашения

Все функции в качестве одного из параметров (format) принимают строку форматирования (описание синтаксиса строки ниже). Возвращают количество записанных (выведенных) символов, не включая нулевой символ в конце. Количество аргументов, содержащих данные для форматированного вывода, должно быть не менее, чем упомянуто в строке форматирования. «Лишние» аргументы игнорируются.

Функции семейства n (snprintf, vsnprintf) возвращают количество символов, которое было бы выведено, если бы параметр n (ограничивающий количество выводимых символов) был достаточно большим. В случае однобайтовых кодировок, возвращаемое значение соответствует необходимому размеру строки (не включая нулевой символ в конце).

Функции семейства s (sprintf, snprintf, vsprintf, vsnprintf) первым параметром (s) принимают указатель на область памяти, куда будет записана результирующая строка. Функции, не имеющие ограничения по количеству записываемых символов являются небезопасными функциями, так как могут привести к ошибке переполнения буфера, в случае, если выводимая строка окажется больше, чем размер выделенной для вывода области памяти.

Функции семейства f записывают строку в любой открытый поток (параметр stream), в частности, в стандартные потоки вывода (stdout, stderr). fprintf(stdout, format, …) эквивалентно printf(format, …).

Функции семейства v принимают аргументы не в виде переменного числа аргументов (как все остальные printf-функции), а в виде списка va list. При этом при вызове функции макрос va end не выполняется.

Функции семейства w (первым символом) являются ограниченной реализацией Microsoft семейства функций s: wsprintf, wnsprintf, wvsprintf, wvnsprintf. Эти функции реализованы в динамических библиотеках user32.dll и shlwapi.dll (n функции). Они не поддерживают вывод значений с плавающей запятой, кроме того, wnsprintf и wvnsprintf поддерживают выравнивание текста только по левому краю.

Функции семейства w (wprintf, swprintf) реализуют поддержку многобайтовых кодировок, все функции этого семейства работают с указателями на многобайтные строки (wchar_t).

Функции семейства a (asprintf, vasprintf) выделяют память для строки вывода при помощи функции malloc, освобождение памяти производится в вызвавшей процедуре, в случае ошибки при выполнении функции память не выделяется.

Описание функций

Имена параметров

  • format — строка форматирования (формат описан ниже)
  • stream — файловый поток для вывода
  • s — строка для помещения результата работы функции
  • n — переменная, содержащая максимальное допустимое количество символов для строки s
  • ap — список значений для вывода
  • strp — указатель на указатель на строку для помещения результатов работы функции

Описание функций

  • int printf( const char *format, ... );
    Вывод форматированной строки на стандартный вывод
  • int fprintf( FILE *stream, const char *format, ... );
    Вывод форматированной строки в поток
  • int sprintf( char *s, const char *format, ... );
    Запись форматированной строки в строку без ограничения по размеру строки
  • int snprintf( char *s, size_t n, const char *format, ... );
    Запись форматированной строки в строку с ограничением по размеру строки
  • int vprintf( const char *format, va_list ap );
    Вывод форматированной строки на стандартный вывод, значения для вывода передаются в функцию в виде списка va list
  • int vfprintf( FILE *stream, const char *format, va_list ap );
    Запись форматированной строки в поток, значения для вывода передаются в функцию в виде списка va list
  • int vsprintf( char *s, const char *format, va_list ap );
    Запись форматированной строки в строку без ограничения размера; значения для вывода передаются в функцию в виде списка va list
  • int vsnprintf( char *s, size_t n, const char *format, va_list ap );
    Запись форматированной строки в строку с ограничением на количество выводимых символов. Значения для вывода передаются в функцию в виде списка va list
  • int fwprintf(FILE *stream, const wchar_t *format, ... );
    Запись форматированной строки многобайтовых символов в файл
  • int swprintf(wchar_t *ws, size_t n, const wchar_t *format, ... );
    Запись форматированной многобайтовой строки в область памяти (Примечание: несмотря на отсутствие буквы n в названии, эта функция принимает параметр, ограничивающий максимальный размер выходной строки).
  • int wprintf(const wchar_t *format, ... );
    Вывод многобайтовой форматированной строки на терминал
  • int wsprintf( LPTSTR s, LPCTSTR format, ... );
    Реализация функции sprintf в операционной системе Windows. В отличие от sprintf не поддерживает вывод значений с плавающей запятой, вывод указателей, дополнительно поддерживает обработку многобайтовых строк в однобайтовой версии функции), не поддерживает флаг '+'.
  • int wnsprintf( LPTSTR s, int n, LPCTSTR format, ... );
    Реализация функции snprintf в операционной системе Windows. Не поддерживает вывод значений с плавающей запятой и указателей, поддерживает только флаг выравнивания по левому краю.
  • int wvsprintf( LPTSTR s, LPCTSTR format, va_list ap );
  • int wvnsprintf( LPTSTR s, int n, LPCTSTR format, va_list ap );
  • int asprintf(char **strp, const char *format, ... );
    функция записывает результат в строку, память для которой выделяется при помощи malloc
  • int vasprintf(char **strp, const char *format, va_list ap);
    функция записывает результат в строку, память для которой выделяется при помощи malloc, значения для вывода передаются в функцию в виде списка va list

Возвращаемое значение: отрицательное значение — признак ошибки; в случае успеха функции возвращают количество записанных/выведенных байтов (без учёта нулевого байта в конце), функция snprintf выводит количество байт, которые были бы записаны, если бы n было бы достаточного размера.

При вызове snprintf, n может быть равно нулю (в этом случае s может быть нулевым указателем), в этом случае запись не производится, функция только возвращает правильное возвращаемое значение.

Синтаксис строки форматирования

В языке Си и Си++ строка форматирования представляет собой строку, завершённую нулевым символом. Все символы, кроме спецификаторов формата, копируются в итоговую строку без изменений. Стандартным признаком начала спецификатора формата является символ % (Знак процента), для вывода самого знака % используется его удвоение %%.

Структура спецификатора формата

Спецификатор формата имеет вид:

%[флаги][ширина][.точность][размер]тип

Обязательными составными частями являются символ начала спецификатора формата (%) и тип.

Флаги

Знак Название знака Значение В отсутствие этого знака Примечание
- дефис выводимое значение выравнивается по левому краю в пределах минимальной ширины поля по правому
+ плюс всегда указывать знак (плюс или минус) для выводимого десятичного числового значения только для отрицательных чисел
  пробел помещать перед результатом пробел, если первый символ значения не знак Вывод может начинаться с цифры. Символ + имеет больший приоритет, чем пробел. Используется только для десятичных числовых значений.
# октоторп «альтернативная форма» вывода значения см. ниже
0 ноль дополнять поле до ширины, указанной в поле ширина управляющей последовательности, символом 0 дополнять пробелами Используется для типов d, i, o, u, x, X, a, A, e, E, f, F, g, G. Для типов d, i, o, u, x, X, если точность указана, этот флаг игнорируется. Для остальных типов поведение не определено.

Модификатор ширины

Ширина (десятичное число или символ звёздочка) указывает минимальную ширину поля (включая знак для чисел). Если представление величины больше, чем ширина поля, то запись выходит за пределы поля (например, %2i для величины 100 даст значение поля в три символа), если представление величины менее указанного числа, то оно будет дополнено (по умолчанию) пробелами слева, поведение может меняться предшествующими флагами. Если в качестве ширины указана звёздочка, ширина поля указывается в списке аргументов перед значением для вывода (например, printf( "%0*x", 8, 15 ); выведет текст 0000000f).

Модификатор точности

  • указывает на минимальное количество символов, которое должно появиться при обработке типов d, i, o, u, x, X;
  • указывает на минимальное количество символов, которое должно появиться после десятичной запятой (точки) при обработке типов a, A, e, E, f, F;
  • максимальное количество значащих символов для типов g и G;
  • максимальное число символов, которые будут выведены для типа s;

Точность задаётся в виде точки с последующим десятичным числом или звёздочкой (*), если число или звёздочка отсутствует (присутствует только точка), то предполагается, что число равно нулю. Точка для указания точности используется даже в том случае, если при выводе чисел с плавающей запятой выводится запятая.

Если после точки указан символ «звёздочка», то при обработке строки форматирования значение для поля читается из списка аргументов. (При этом, если символ звёздочка и в поле ширины и в поле точности, сначала указывается ширина, потом точность и лишь потом значение для вывода). Например, printf( "%0*.*f", 8, 4, 2.5 ); выведет текст 002.5000.

Модификатор размера

Поле размер позволяет указать размер данных, переданных функции. Необходимость в этом поле объясняется особенностями передачи произвольного количества параметров в функцию в языке Си: функция не может «самостоятельно» определить тип и размер переданных данных, так что информация о типе параметров и точном их размере должна передаваться явно.

Рассматривая влияние размерных спецификаций на форматирование целочисленных данных, нужно отметить, что в языке Си имеется цепочка пар знаковых и беззнаковых целых типов, которые в порядке неубывания размеров располагаются так:
Знаковый тип Беззнаковый тип
signed char unsigned char
signed short (short) unsigned short int (unsigned short)
signed int (int) unsigned int (unsigned)
signed long int (long) unsigned long int (unsigned long)
signed long long int (long long) unsigned long long int (unsigned long long)

Точные размеры типов неизвестны за исключением типов signed char и unsigned char.

Парные знаковый и беззнаковый типы имеют одинаковый размер, а значения, представимые в обоих типах, имеют в них одинаковое представление.

Тип char имеет одинаковый размер с типами signed char и unsigned char и общий набор представимых значений с одним из этих типов. Далее считается, что char — другое имя одного из этих типов; такое допущение приемлемо для настоящего рассмотрения.

Си++ имеет тот же набор типов, за исключением пары long long и unsigned long long. Впрочем, эти типы могут присутствовать в реализациях на правах языковых расширений.

Кроме того, в языке Си присутствует тип _Bool, а в Си++ — bool.

При передаче в функцию аргументов, которым не соответствуют формальные параметры в прототипе функции (а таковыми являются все аргументы, содержащие выводимые значения), эти аргументы подвергаются стандартным продвижениям, а именно:

  • аргументы типа float приводятся к типу double;
  • аргументы типов unsigned char, unsigned short, signed char и short приводятся к одному из следующих типов:
    • int, если этот тип способен представить все значения исходного типа, или
    • unsigned в противном случае;
  • аргументы типов _Bool или bool приводятся к типу int.
Таким образом, функции printf не могут получать аргументов типов float, _Bool или bool или целочисленных типов меньших, чем int или unsigned.

Набор применяемых спецификаторов размера зависит от спецификатора типа (см. ниже).

Спецификатор %d, %i, %o, %u, %x, %X %n Примечание
отсутствует int или unsigned int указатель на int
l long int или unsigned long int указатель на long int
hh Аргумент имеет тип int или unsigned int, но принудительно приводится к типу signed char или unsigned char, соответственно указатель на signed char формально существуют только в языке Си начиная со второго стандарта (1999)
h Аргумент имеет тип int или unsigned int, но принудительно приводится к типу short int или unsigned short int, соответственно указатель на short int
ll long long int или unsigned long long int указатель на long long int
j intmax_t или uintmax_t указатель на intmax_t
z size_t (или эквивалентный по размеру знаковый тип) указатель на эквивалентный по размеру size_t знаковый тип
t ptrdiff_t (или эквивалентный по размеру беззнаковый тип) указатель на ptrdiff_t
L __int64 или unsigned __int64 указатель на __int64 Для Borland Builder 6 (спецификатор ll ожидает 32-бит число)

Спецификации h и hh используются для компенсации стандартных продвижений типов в сочетании с переходами от знаковых типов к беззнаковым или наоборот.

Например, рассмотрим реализацию Си, где тип char знаковый и имеет размер 8 бит, тип int имеет размер 32 бит, используется дополнительный способ кодирования отрицательных целых.
char c = 255;
printf("%X", c);

Такой вызов даст вывод FFFFFFFF, что, возможно, не то, чего ожидал программист. Действительно, значение c равно (char)(-1), а после продвижения типа оно оказывается равно -1. Применение формата %X вызывает интерпретацию данного значения как беззнакового, то есть, 0xFFFFFFFF.

char c = 255;
printf("%X", (unsigned char)c);
char c = 255;
printf("%hhX", c);
Эти два вызова имеют один и тот же эффект и дают вывод FF. Первый вариант позволяет избежать размножения знака при продвижении типа, второй — компенсирует его уже «внутри» функции printf.
Спецификатор %a, %A, %e, %E, %f, %F, %g, %G
отсутствует double
L long double
Спецификатор %c %s
отсутствует Аргумент имеет тип int или unsigned int, но принудительно приводится к типу char char*
l Аргумент имеет тип wint_t, но принудительно приводится к типу wchar_t wchar_t*

Спецификатор типа

Тип указывает не только на тип величины (с точки зрения языка программирования Си), но и на конкретное представление выводимой величины (например, числа могут выводить в десятичном или шестнадцатеричном виде). Записывается в виде одного символа. В отличие от остальных полей является обязательным. Максимальный поддерживаемый размер вывода от единичной управляющей последовательности составляет по стандартам как минимум 4095 символов; на практике большинство компиляторов поддерживают существенно большие объёмы данных.

Значения типов:

  • d, i — десятичное знаковое число, размер по умолчанию, sizeof( int ). По умолчанию записывается с правым выравниванием, знак пишется только для отрицательных чисел. '%d' и '%i' ведут себя одинаково при выводе, но имеют разные значения при вводе с помощью функции scanf();
  • o — восьмеричное беззнаковое число, размер по умолчанию sizeof( int );
  • u — десятичное беззнаковое число, размер по умолчанию sizeof( int );
  • x и X — шестнадцатеричное число, x использует маленькие буквы (abcdef), X большие (ABCDEF), размер по умолчанию sizeof( int );
  • f и F — числа с плавающей запятой. По умолчанию выводятся с точностью 6, если число по модулю меньше единицы, перед десятичной точкой пишется 0. Величины ±∞ представляются в форме [-]inf или [-]infinity, Величина Nan представляется как [-]nan или [-]nan(любой текст далее). Использование F выводит указанные величины заглавными буквами (-INF, NAN). Аргумент по умолчанию имеет размер double.
  • e и E — числа с плавающей запятой в экспоненциальной форме записи (вида 1.1e+44); e выводит символ «e» в нижнем регистре, E — в верхнем (3.14E+0);
  • g и G — число с плавающей запятой; форма представления зависит от значения величины (f или e);
  • a и A — число с плавающей запятой в шестнадцатеричном виде;
  • c — вывод символа с кодом, соответствующим переданному аргументу; переданное число приводится к типу unsigned char (или wchar t, если был указан модификатор длины l);
  • s — вывод строки с нулевым завершающим байтом; если модификатор длины — l, выводится строка wchar_t*. В Windows значения типа s зависят от типа используемых функций. Если используется семейство printf функций, то s обозначает строку char*. Если используется семейство wprintf функций, то s обозначает строку wchar_t*.
  • S — то же самое что и s с модификатором длины l; В Windows значения типа S зависит от типа используемых функций. Если используется семейство printf функций, то S обозначает строку wchar_t*. Если используется семейство wprintf функций, то S обозначает строку char*.
  • p — вывод указателя, внешний вид может существенно различаться в зависимости от внутреннего представления в компиляторе и платформе (например, 16 битная платформа MS-DOS использует форму записи вида FFEC:1003, 32-битная платформа с плоской адресацией использует адрес вида 00FA0030);
  • n — запись по указателю, переданному в качестве аргумента, количества символов, записанных на момент появления командной последовательности, содержащей n;
  • % — символ для вывода знака процента (%), используется для возможности вывода символов процента в строке printf, всегда используется в виде %%.
Вывод чисел с плавающей запятой

В зависимости от текущей локали, при выводе чисел с плавающей запятой может использоваться как запятая, так и точка (а, возможно, и другой символ). Поведение printf в отношении разделяющего дробную и целую часть числа символа определяется использующейся локалью (точнее, переменной LC NUMERIC).[17]

Специальные макросы для расширенного набора псевдонимов целочисленных типов данных

Второй стандарт языка Си (1999) предусматривает расширенный набор псевдонимов целочисленных типов данных intN_t, uintN_t, int_leastN_t, uint_leastN_t, int_fastN_t, uint_fastN_t (где N — требуемая разрядность), intptr_t, uintptr_t, intmax_t, uintmax_t.

Каждый из этих типов может совпадать или не совпадать с каким-либо стандартным встроенным целочисленным типом. Формально говоря, при написании переносимого программного кода программист не знает заведомо, какую стандартную или расширенную спецификацию размера ему следует применить.

int64_t x = 100000000000;
int width=20;
printf("%0*lli", width, x);
Неправильно, так как тип int64_t может не совпадать с типом long long int.

Для того, чтобы иметь возможность переносимым и удобным образом выводить значения объектов или выражений этих типов, реализация определяет для каждого из этих типов набор макросов, значением которых являются строки, объединяющие спецификации размера и типа.

Имена макросов имеют следующий вид:

Пара знакового и беззнакового типов Имя макроса
intN_t и uintN_t PRITN
int_leastN_t и uint_leastN_t PRITLEASTN
int_fastN_t и uint_fastN_t PRITFASTN
intmax_t и uintmax_t PRITMAX
intptr_t и uintptr_t PRITPTR

Здесь T — одна из следующих спецификаций типа: d, i, u, o, x, X.

int64_t x = 100000000000;
int width=20;
printf("%0*"PRIi64, width, x);
Правильный способ вывода значения типа int64_t в языке Си.

Можно заметить, что для типов intmax_t и uintmax_t имеется стандартный спецификатор размера j, поэтому макрос PRITMAX, скорее всего, всегда определён как "jT".

XSI расширения в стандарте Single Unix

В рамках стандарта Single UNIX (практически эквивалентного стандарту POSIX), определены следующие дополнения printf по отношению к ISO C, в рамках расширения XSI (X/Open System Interface):

  • Добавляется возможность вывода произвольного по номеру параметра (указывается в виде n$ сразу после символа начала управляющей последовательности, например, printf("%1$d:%2$.*3$d:%4$.*3$d\n", hour, min, precision, sec);).
  • Добавлен флаг «'» (одинарная кавычка), который для типов d, i, o, u предписывает разделять классы соответствующим символом.
  • тип C, эквивалентный lc ISO C (вывод символа типа wint_t).
  • тип S, эквивалентный ls ISO C (вывод строки типа wchar_t*)
  • Добавлены коды ошибок EILSEQ, EINVAL, ENOMEM, EOVERFLOW.

Нестандартные расширения

GNU C Library

В рамках GNU C Library (libc) добавлены следующие расширения:

  • тип m выводит значение глобальной переменной errno (код ошибки последней функции).
  • тип C эквивалентен lc.
  • флаг ' (одинарная кавычка) используется для разделения классов при выводе чисел. Формат разделения зависит от LC_NUMERIC
  • размер q указывает на тип long long int (на системах, где не поддерживается тип long long int, это то же самое, что и long int
  • размер Z является псевдонимом для z, был введён в libc до появления стандарта C99, не рекомендуется к использованию в новом коде.
Регистрация собственных типов

GNU libc поддерживает регистрацию пользовательских типов, позволяя программисту определять формат вывода для собственных структур данных. Для регистрации нового типа используется функция
int register_printf_function (int type, printf_function handler-function, printf_arginfo_function arginfo-function), где:

  • type — буква для типа (если type = 'Y', то вызов будет выглядеть как '%Y');
  • handler-function — указатель на функцию, которая вызывается, printf-функциями, если в строке форматирования встречается тип, указанный в type;
  • arginfo-function — указатель на функцию, которая будет вызываться функцией parse_printf_format.

Помимо определения новых типов регистрация позволяет переопределить существующие типы (такие, как s, i).

Microsoft Visual C

В составе Microsoft Visual Studio для языков программирования Си/Си++ в формате спецификации printf (и остальных функций семейства) предусмотрены следующие расширения:

  • поле размера:
значение поля тип
I32 signed __int32, unsigned __int32
I64 signed __int64, unsigned __int64
I ptrdiff_t, size_t
w эквивалентно l для строк и символов

Maple

В среде математических вычислений Maple также имеется функция printf, она имеет следующие особенности:

Форматирование
    •  %a, %A: объект Maple будет выдан в текстовой нотации, это работает для всех объектов (например, матриц, функций, модулей и т. д.). Строчная буква предписывает окружать обратными апострофами символы (имена), которые должны быть окружены ими на входе printf.
    •  %q, %Q: то же, что и %a/%A, но обрабатываться будет не один аргумент, а все начиная с того, которому соответствует флаг форматирования. Таким образом, флаг %Q/%q может стоять только последним в строке формата.
    •  %m: форматировать объект в соответствии с его внутренним для Maple представлением. Практически используется для записи переменных в файл.

Пример:

> printf("%a =%A", `+`, `+`);
`+` = +
> printf("%a =%m", `+`, `+`);
`+` = I"+f*6"F$6#%(builtinGF$"$Q"F$F$F$F"%*protectedG
Вывод

Функция fprintf в maple в первом аргументе принимает либо дескриптор файла (возвращаемый функцией fopen), либо имя файла. В последнем случае имя должно иметь тип «символ», если имя файла содержит точки, то его обязательно нужно заключить в обратные апострофы или преобразовать функцией convert(имя_файла, symbol).

Уязвимости

Функции семейства printf принимают список аргументов и их размер отдельным параметром (в строке форматирования). Несоответствие строки форматирования и переданных аргументов может приводить к непредсказуемому поведению, повреждению стека и выполнению произвольного кода, приводить к разрушению областей динамической памяти. Многие функции семейства называются «небезопасными» (англ. unsafe), так как не имеют даже теоретической возможности для защиты от некорректных данных.

Так же функции семейства s (без n, такие как sprintf, vsprintf) не имеют ограничителей по максимальному размеру записываемой строки и могут приводить к ошибке переполнения буфера (когда данные записываются за пределы отведённой области памяти).

Поведение при несоответствии строки форматирования и переданных аргументов

В рамках соглашения о вызове cdecl, очистку стека осуществляет вызвавшая функция. При вызове printf аргументы (или указатели на них) помещаются в порядке следования записи (слева направо). По мере обработки строки форматирования функция printf читает аргументы со стека. Возможны следующие ситуации:

  • количество и тип аргументов совпадают с указанными в строке форматирования (нормальная работа функции)
  • в функцию передано больше аргументов, чем указано в строке форматирования (лишние аргументы)
  • в функцию передано меньше аргументов, чем требуется согласно строке форматирования (недостаток аргументов)
  • в функцию переданы аргументы неправильного размера
  • в функцию переданы аргументы правильного размера, но неправильного типа

Спецификации языка Си описывают только две ситуации (нормальной работы и лишних аргументов). Все остальные ситуации являются ошибочными и приводят к неопределённому поведению программы (в реальности приводящему к произвольным результатам, вплоть до выполнения незапланированных участков кода).

Избыточное количество аргументов

При передаче излишнего количества аргументов, функция printf читает аргументы, требующиеся для правильной обработки строки форматирования, возвращает управление вызвавшей функции. Вызвавшая функция, в соответствии со спецификацией, очищает стек от параметров, переданных в вызываемую функцию. В этом случае лишние параметры просто не используются, и работа программы продолжается без изменений.

Недостаточное количество аргументов

Если при вызове printf аргументов в стеке меньше, чем требуется для обработки строки форматирования, то недостающие аргументы читаются со стека, несмотря на то, что на стеке находятся произвольные данные (не имеющие отношения к работе printf). Если обработка данных прошла «успешно» (то есть не привела к прекращению работы программы, зависанию или записи в стек), после возврата в вызывающую функцию значение указателя стека возвращается в исходное, и работа программы продолжается.

При обработке «лишних» значений стека, возможны следующие ситуации:

  • успешное чтение «лишнего» параметра для вывода (число, указатель, символ и т. д.) — в результаты вывода помещается «почти случайное» значение, прочитанное со стека. Это не представляет собой опасности для работы программы, но может приводить к компрометации каких-либо данных (вывод значений стека, которые может использовать злоумышленник для анализа работы программы и получению доступа к внутренней/закрытой информации программы).
  • ошибка при чтении значения со стека (например, в результате исчерпания доступных значений стека или доступ к «несуществующим» страницам памяти) — такая ошибка вероятнее всего приведёт к аварийному завершению работы программы.
  • чтение указателя на параметр. Строки передаются с помощью указателя, при чтении «произвольной» информации со стека, прочитанное (почти случайное) значение используется как указатель на случайную область памяти. Поведение программы в этом случае не определено и зависит от содержимого этой области памяти.
  • запись параметра по указателю (%n) — в данном случае поведение аналогично ситуации с чтением, но осложняется возможными сторонними эффектами записи в произвольную ячейку памяти.

Несоответствие типов аргументов

Формально любое несоответствие типа аргумента ожиданию вызывает неопределённое поведение программы. На практике можно выделить несколько особо интересных с точки зрения программистской практики случаев:

  • Аргумент имеет тот же тип, что и ожидается, но другой размер.
  • Аргумент имеет тот же размер, что и ожидается, но другой тип.

Иные случаи, как правило, приводят к очевидно некорректному поведению, и легко выявляются.

Несоответствие размера целочисленного аргумента или аргумента с плавающей точкой

Для целочисленного аргумента (при целочисленной же форматной спецификации) возможны следующие ситуации:

  • Передача параметров, размер которых больше ожидаемого (чтение меньшего из большего). При этом, в зависимости от принятого порядка байтов и направления роста стека, выведенное значение может как совпасть со значением аргумента, так и оказаться не имеющим к нему отношения.
  • Передача параметров, размер которых меньше ожидаемого (чтение большего из меньшего). В этом случае возможна ситуация, когда читаются области стека, выходящие за пределы переданных аргументов. Поведение функции в этом случае аналогично поведению в ситуации с недостатком параметров. В общем случае выводимое значение не соответствует ожидаемому.

Для вещественного аргумента (при вещественной же форматной спецификации) при любом несовпадении размеров выводимое значение, как правило, не совпадает с переданным.

Как правило, при ошибке размера какого-то одного аргумента правильная обработка всех последующих аргументов становится невозможной, так как в указатель на аргументы вносится ошибка. Однако этот эффект может быть нивелирован выравниванием значений на стеке.

Выравнивание значений на стеке

На многих платформах действуют правила выравнивания целочисленных и/или вещественных значений, требующие (или рекомендующие) их размещения по адресам, кратным их размеру. Эти правила распространяются и на передачу аргументов функций через стек. В этом случае ряд несовпадений типов ожидаемых и фактических параметров может оставаться незамеченным, создавая иллюзию правильности программы.

uint32_t a = 1;
uint64_t b = 2, c = 3;
printf("%"PRId64"%"PRId64"%"PRId64, b, a, c);
В данном примере фактическому параметру a типа uint32_t сопоставлена неверная форматная спецификация %"PRId64", предусмотренная для типа uint64_t. Тем не менее, на ряде платформ c 32-разрядным типом int, в зависимости от принятого порядка байт и направления роста стека, ошибка может оставаться незамеченной. Фактические параметры b и c будут выравнены по адресу, кратному их размеру (вдвое больше размера a). А «между» значениями a и b будет оставлено пустое (как правило, занулённое) пространство размером в 32 бита; при обработке спецификации %"PRId64" 32-разрядное значение a вместе с этим пустым пространством будут истолкованы как единое 64-разрядное значение.

Подобная ошибка может неожиданно проявиться при переносе программного кода на другую платформу, смене компилятора или режима компиляции.

Потенциальное несоответствие размеров

Определения языков Си и Си++ описывают лишь наиболее общие требования к размерам и представлению типов данных. Поэтому на многих платформах представление некоторых формально разных типов данных оказываются одинаковыми. Это приводит к тому, что некоторые несовпадения типов могут долгое время оставаться необнаружимыми.

Например, на платформе Win32 общепринято, что размеры типов int и long int совпадают (32 разряда). Так, вызов printf("%ld", 1) или printf("%d", 1L) будет выполнен «правильно».

Подобная ошибка может неожиданно проявиться при переносе программного кода на другую платформу, смене компилятора или режима компиляции.

При написании программ на языке Си++ нужно внимательно относиться к выводу значений переменных, объявленных при помощи псевдонимов целочисленных типов, в частности size_t и ptrdiff_t; формальное определение стандартной библиотеки Си++ ссылается на первый стандарт языка Си (1990). Во втором стандарте языка Си (1999) для типов size_t и ptrdiff_t и для ряда иных типов определены спецификаторы размера для использования с подобными объектами. Многие реализации Си++ их также поддерживают.

size_t s = 1;
printf("%u", s);
Данный пример содержит ошибку, способную проявиться на платформах, где sizeof (unsigned int) не равно sizeof (size_t).
size_t s = 1;
printf("%zu", s);
Правильный способ вывести значение объекта типа size_t в языке Си.

Несоответствие типов при совпадении размеров

Если переданные аргументы совпадают по размеру, но имеют отличный тип, то часто работа программы будет «почти правильной» (не вызовет ошибок доступа к памяти), хотя выводимое значение, вероятнее всего, будет бессмысленным. Надо отметить, что смешение па́рных друг другу целочисленных типов (знакового и беззнакового) допустимо, неопределённого поведения не вызывает, и иногда сознательно используется в практике.

При использовании форматной спецификации %s значение аргумента целочисленного, вещественного типа или типа указателя иного нежели char*, будет проинтерпретировано как адрес строки. Этот адрес, вообще говоря, может произвольно указывать на несуществующую или недоступную область памяти, что приведёт к ошибке доступа к памяти, либо на область памяти, не содержащую строки, что приведёт к выводу бессмыслицы, возможно, очень объёмному.

Уязвимость строки форматирования

Так как printf (и остальные функции семейства) могут выводить текст строки форматирования без изменений, если он не содержит управляющих последовательностей, то возможен вывод текста командой
printf(text_to_print);
В случае, если text_to_print получается из внешних источников (читается из файла, получается от пользователя или операционной системы), то наличие в получаемой строке знака процента может приводить к крайне нежелательным последствиям (вплоть до зависания программы).

Пример некорректного кода:
printf(" Current status: 99% stored.");
В этом примере содержится управляющая последовательность «% s», содержащая признак управляющей последовательности (%), флаг (пробел) и тип данных «строка» (s). Функция, приняв управляющую последовательность, попытается прочитать из стека указатель на строку. Так как функции не передавались дополнительные параметры, значение, которое будет прочитано со стека, не определено. Полученное значение будет интерпретировано как указатель на строку с завершающим нулём. Вывод такой «строки» может привести к выводу произвольного дампа памяти, ошибке доступа к памяти и разрушению стека. Такой тип уязвимости называют атакой на строку форматирования (англ. Format string attack).[18]

Переполнение буфера

Функция printf при выводе результата не ограничивается по максимальному количеству выводимых символов. Если в результате ошибки или недосмотра будет выведено больше символов, чем ожидалось, худшее, что может случиться — это «разрушение» картинки на экране. Созданная по аналогии с printf функция sprintf также не ограничивалась в максимальном размере результирующей строки. Однако в отличие от «бесконечного» терминала, память, которую выделяет приложение для результирующей строки, всегда ограничена. И в случае выхода за ожидаемые рамки, запись производится в области памяти, принадлежащие другим структурам данных (или, вообще, в недоступные участки памяти, что практически на всех платформах означает аварийное завершение программы). Запись в произвольные области памяти приводит к непредсказуемым эффектам (которые, возможно, проявятся много позже и не в форме ошибки программы, а в форме повреждения пользовательских данных). Отсутствие ограничения на максимальный размер строки является принципиальной ошибкой планирования при разработке функции. Именно из-за этого функции sprintf и vsprintf имеют статус небезопасных. Взамен им были разработаны функции snprintf, vsnprintf, принимающие дополнительный аргумент, ограничивающий максимальную результирующую строку. Появившаяся много позже функция swprintf (для работы с многобайтными кодировками) учитывает эту недоработку и принимает аргумент для ограничения результирующей строки. (Именно поэтому нет функции snwprintf).

Пример опасного вызова sprintf:

char buffer[65536];
char* name = get_user_name_from_keyboard();
sprintf(buffer, "User name:%s", name);

В вышеприведённом коде неявно предполагается, что пользователь не будет печатать 65 тысяч символов на клавиатуре, и буфера «должно хватить». Но пользователь может перенаправить ввод из другой программы или всё-таки ввести более 65 тысяч символов. В этом случае произойдёт повреждение областей памяти и поведение программы станет непредсказуемым.

Сложности в использовании

Отсутствие контроля типов

Функции семейства printf используют типы данных языка Си, размер типов, и соотношение размеров типов может меняться от платформы к платформе. Например, на 64-битных платформах в зависимости от выбранной модели (LP64, LLP64 или ILP64) размеры типов int и long могут различаться. Если программист задаст форматную строку «почти правильно», код будет работать на одной платформе и выдавать неправильный результат на другой (в ряде случаев, возможно, приводя к повреждению данных).

Например, код printf( "text address: 0x%X", "text line" ); работает правильно на 32-битной платформе (размер ptrdiff_t и размер int 32 бита) и на 64-битной модели IPL64 (где размеры ptrdiff_t и int 64 бита), но даст неверный результат на 64-битной платформе модели LP64 или LLP64, где размер ptrdiff_t 64 бита, а размер int 32 бита.[19]

В Oracle Java в аналоге функции printf применяются обёрнутые типы с динамической идентификацией,[6] в Embarcadero Delphi — промежуточная прослойка array of const,[20] в различных реализациях на C++[21] — перегрузка операций. К тому же форматы (%d, %f и т. д.) задают не тип аргумента, а лишь формат вывода, так что замена типа аргумента может вызвать аварийную ситуацию или нарушить высокоуровневую логику (например, «сломать» вёрстку таблицы) — но не испортить память.

Недостаточная стандартизация

Проблема усугубляется недостаточной стандартизацией форматных строк в разных компиляторах: например, ранние версии библиотек Microsoft не поддерживали "%lld" (приходилось указывать "%I64d"). Всё ещё есть разделение между Microsoft и GNU по типу size_t: %Iu у первого и %zu у второго. GNU C не требует в функции swprintf максимальную длину строки (приходится писать snwprintf).

Невозможность переставить аргументы местами

Функции семейства printf удобны для локализации программного обеспечения: например, проще перевести «You hit %s instead of %s.», чем обрывки строк «You hit », « instead of » и «.». Но и здесь таится проблема: невозможно переставить подставляемые строки местами, чтобы получилось: «Вы попали не в <2>, а в <1>.».

Расширения printf, применяемые в Oracle Java и Embarcadero Delphi, всё-таки позволяют переставить аргументы местами.

Утилита printf

В рамках стандарта POSIX описана утилита printf, которая форматирует аргументы по соответствующему шаблону, аналогично функции printf.

Утилита имеет следующий формат вызова: printf format [argument …], где

  • format — строка формата, по синтаксису похожая на строку формата функции printf.
  • argument — список аргументов (0 или более), записанных в строковой форме.

Примеры реализации

  • [www.ijs.si/software/snprintf/]
  • [daniel.haxx.se/projects/trio/]

Пример 1 Си (язык программирования)

#include <stdio.h>
#include <locale.h>

#define PI 3.141593

int main()
{
	setlocale(LC_ALL, "RUS");
	int number = 7;
	float pies = 12.75;
	int cost = 7800;
	printf("%d участников соревнований съели %f пирожков с вишнями.\n", number, pies);
	printf("Значение pi равно %f\n", PI);
	printf("До свидания! Ваше искусство слишком дорого обходится (%c%d)\n", '$', 2 * cost);

	return 0;
}

Пример 2 Си (язык программирования)

#include <stdio.h>

#define PAGES 959

int main()
{
	printf("*%d*\n", PAGES);
	printf("*%2d*\n", PAGES);
	printf("*%10d*\n", PAGES);
	printf("*%-10d*\n", PAGES);

	return 0;
}
/*
Результат:
*959*
*959*
*       959*
*959       *
*/

Пример 3 Си (язык программирования)

#include <stdio.h>

#define BLURB "Authentic imitation!"

int main()
{
	const double RENT = 3852.99;
	printf("*%8f*\n", RENT);
	printf("*%e*\n", RENT);
	printf("*%4.2f*\n", RENT);
	printf("*%3.1f*\n", RENT);
	printf("*%10.3f*\n", RENT);
	printf("*%10.3E*\n", RENT);
	printf("*%+4.2f*\n", RENT);

	printf("%x %X %#x\n", 31, 31, 31);
	printf("**%d**% d% d **\n", 42, 42, -42);
	printf("**%5d**%5.3d**%05d**%05.3d**\n", 6, 6, 6, 6);
	printf("\n");

	printf("[%2s]\n", BLURB);
	printf("[%24s]\n", BLURB);
	printf("[%24.5s]\n", BLURB);
	printf("[%-24.5s]\n", BLURB);

	return 0;
}

Напишите отзыв о статье "Printf"

Ссылки

  1. [www.lysator.liu.se/c/clive-on-bcpl.html Краткое описание языка BCPL]
  2. [cm.bell-labs.com/cm/cs/who/dmr/kbman.html Руководство по языку Би]
  3. [search.cpan.org/dist/perl/pod/perlfunc.pod#sprintf Описание функции sprintf в документации Perl]
  4. [www.python.org/doc/current/lib/typesseq-strings.html Описание форматирующего оператора для строковых типов в Питоне]
  5. [ru.php.net/manual/ru/function.printf.php Описание функции printf в составе PHP]
  6. 1 2 [java.sun.com/j2se/1.5.0/docs/api/java/io/PrintStream.html#printf(java.lang.String,%20java.lang.Object...) Описание функции java.io.PrintStream.printf() в Java 1.5]
  7. [www.ruby-doc.org/docs/ruby-doc-bundle/Manual/man-1.4/function.html#printf Описание функции printf в документации Ruby]
  8. [www.lua.org/manual/5.1/manual.html#pdf-string.format Описание функции string.format в документации Lua]
  9. [www.tcl.tk/man/tcl/TclCmd/format.htm Описание функции format в документации TCL]
  10. [www.delorie.com/gnu/docs/octave/octave_111.html Описание шаблона строки для printf в документации GNU Octave]
  11. Описание printf в документации к Maple{{подст:АИ}}
  12. R. Fourer, D.M. Gay, and B.W. Kernighan. AMPL: A Modeling Language for Mathematical Programming, 2nd Ed.. Pacific Grove, CA: Brooks/Cole--Thomson Learning, 2003.
  13. GNU Emacs Lisp Reference Manual, [www.delorie.com/gnu/docs/elisp-manual-21/elisp_75.html Formatting Strings]
  14. [caml.inria.fr/pub/docs/manual-ocaml/libref/Printf.html Описание модуля Printf в документации OCaml]
  15. [hackage.haskell.org/package/base-4.8.0.0/docs/Text-Printf.html Описание модуля Printf в документации Haskell]
  16. [doc.rust-lang.org/std/macro.println!.html std::println! - Rust]. doc.rust-lang.org. Проверено 24 июля 2016.
  17. § 7.11.1.1 ISO/IEC 9899:TC2, LC_NUMERIC определяет, в частности, форму представления разделителя дробной и целой части.
  18. Описание уязвимостей printf, Robert C. Seacord: Secure Coding in C and C++. Addison Wesley, September, 2005. ISBN 0-321-33572-4
  19. [www-128.ibm.com/developerworks/ru/library/l-port64/index.html Описание проблем переноса приложений с 32 на 64 битную архитектуру]
  20. [docwiki.embarcadero.com/Libraries/XE2/en/System.SysUtils.Format System.SysUtils.Format] (англ.)
  21. Например, boost::format, [www.boost.org/doc/libs/1_53_0/libs/format/doc/format.html документация] (англ.)

Источники

  • printf, fprintf, snprintf, vfprintf, vprintf, vsnprintf, vsprintf в стандарте ISO/IEC 9899:TC2 (ISO C) [www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf]
  • printf, fprintf, sprintf, snprintf в стандарте Single Unix [www.opengroup.org/onlinepubs/009695399/functions/printf.html]
  • vprintf, vfprintf, vsprintf, vsnprintf в стандарте POSIX [www.opengroup.org/onlinepubs/009695399/functions/vprintf.html]
  • wprintf, swprintf, wprintf в стандарте POSIX [www.opengroup.org/onlinepubs/009695399/functions/wprintf.html]
  • vfwprintf, vswprintf, vwprintf в стандарте POSIX [www.opengroup.org/onlinepubs/009695399/functions/vwprintf.html]
  • wsprintf в MSDN [msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/resources/strings/stringreference/stringfunctions/wsprintf.asp]
  • wvnsprintf в MSDN [msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/shlwapi/string/wnsprintf.asp]
  • wnsprintf в MSDN [msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/shlwapi/string/wnsprintf.asp]
  • wvsprintf в MSDN [msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/resources/strings/stringreference/stringfunctions/wsprintf.asp]
  • wnsprintf в MSDN [msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/resources/strings/stringreference/stringfunctions/wsprintf.asp]
  • asprintf, vasprintf в man-pages в Linux [www.linuxdoc.ru/manpages/man3/asprintf.3.html], в документации к libc [www.gnu.org/software/libc/manual/html_node/Dynamic-Output.html#Dynamic-Output]
  • Описание синтаксиса строки форматирования в руководстве libc [www.gnu.org/software/libc/manual/html_node/Formatted-Output.html].
  • Описание строки форматирования в документации к Microsoft Visual Studio 2005 [msdn2.microsoft.com/en-us/library/56e442dc(VS.80).aspx]
  • Описание register_printf_function [www.gnu.org/software/libc/manual/html_node/Registering-New-Conversions.html], [www.gnu.org/software/libc/manual/html_node/Defining-the-Output-Handler.html]
  • Язык программирования C. Лекции и упражнения. Автор: Стивен Прата. ISBN 978-5-8459-1950-2 , 978-0-321-92842-9; 2015 г.

См. также

Отрывок, характеризующий Printf

– А много вашей силы тут? – спросил другой небольшой мужик, подходя к ним.
– Много, много, – отвечал Ростов. – Да вы что ж собрались тут? – прибавил он. – Праздник, что ль?
– Старички собрались, по мирскому делу, – отвечал мужик, отходя от него.
В это время по дороге от барского дома показались две женщины и человек в белой шляпе, шедшие к офицерам.
– В розовом моя, чур не отбивать! – сказал Ильин, заметив решительно подвигавшуюся к нему Дуняшу.
– Наша будет! – подмигнув, сказал Ильину Лаврушка.
– Что, моя красавица, нужно? – сказал Ильин, улыбаясь.
– Княжна приказали узнать, какого вы полка и ваши фамилии?
– Это граф Ростов, эскадронный командир, а я ваш покорный слуга.
– Бе…се…е…ду…шка! – распевал пьяный мужик, счастливо улыбаясь и глядя на Ильина, разговаривающего с девушкой. Вслед за Дуняшей подошел к Ростову Алпатыч, еще издали сняв свою шляпу.
– Осмелюсь обеспокоить, ваше благородие, – сказал он с почтительностью, но с относительным пренебрежением к юности этого офицера и заложив руку за пазуху. – Моя госпожа, дочь скончавшегося сего пятнадцатого числа генерал аншефа князя Николая Андреевича Болконского, находясь в затруднении по случаю невежества этих лиц, – он указал на мужиков, – просит вас пожаловать… не угодно ли будет, – с грустной улыбкой сказал Алпатыч, – отъехать несколько, а то не так удобно при… – Алпатыч указал на двух мужиков, которые сзади так и носились около него, как слепни около лошади.
– А!.. Алпатыч… А? Яков Алпатыч!.. Важно! прости ради Христа. Важно! А?.. – говорили мужики, радостно улыбаясь ему. Ростов посмотрел на пьяных стариков и улыбнулся.
– Или, может, это утешает ваше сиятельство? – сказал Яков Алпатыч с степенным видом, не заложенной за пазуху рукой указывая на стариков.
– Нет, тут утешенья мало, – сказал Ростов и отъехал. – В чем дело? – спросил он.
– Осмелюсь доложить вашему сиятельству, что грубый народ здешний не желает выпустить госпожу из имения и угрожает отпречь лошадей, так что с утра все уложено и ее сиятельство не могут выехать.
– Не может быть! – вскрикнул Ростов.
– Имею честь докладывать вам сущую правду, – повторил Алпатыч.
Ростов слез с лошади и, передав ее вестовому, пошел с Алпатычем к дому, расспрашивая его о подробностях дела. Действительно, вчерашнее предложение княжны мужикам хлеба, ее объяснение с Дроном и с сходкою так испортили дело, что Дрон окончательно сдал ключи, присоединился к мужикам и не являлся по требованию Алпатыча и что поутру, когда княжна велела закладывать, чтобы ехать, мужики вышли большой толпой к амбару и выслали сказать, что они не выпустят княжны из деревни, что есть приказ, чтобы не вывозиться, и они выпрягут лошадей. Алпатыч выходил к ним, усовещивая их, но ему отвечали (больше всех говорил Карп; Дрон не показывался из толпы), что княжну нельзя выпустить, что на то приказ есть; а что пускай княжна остается, и они по старому будут служить ей и во всем повиноваться.
В ту минуту, когда Ростов и Ильин проскакали по дороге, княжна Марья, несмотря на отговариванье Алпатыча, няни и девушек, велела закладывать и хотела ехать; но, увидав проскакавших кавалеристов, их приняли за французов, кучера разбежались, и в доме поднялся плач женщин.
– Батюшка! отец родной! бог тебя послал, – говорили умиленные голоса, в то время как Ростов проходил через переднюю.
Княжна Марья, потерянная и бессильная, сидела в зале, в то время как к ней ввели Ростова. Она не понимала, кто он, и зачем он, и что с нею будет. Увидав его русское лицо и по входу его и первым сказанным словам признав его за человека своего круга, она взглянула на него своим глубоким и лучистым взглядом и начала говорить обрывавшимся и дрожавшим от волнения голосом. Ростову тотчас же представилось что то романическое в этой встрече. «Беззащитная, убитая горем девушка, одна, оставленная на произвол грубых, бунтующих мужиков! И какая то странная судьба натолкнула меня сюда! – думал Ростов, слушяя ее и глядя на нее. – И какая кротость, благородство в ее чертах и в выражении! – думал он, слушая ее робкий рассказ.
Когда она заговорила о том, что все это случилось на другой день после похорон отца, ее голос задрожал. Она отвернулась и потом, как бы боясь, чтобы Ростов не принял ее слова за желание разжалобить его, вопросительно испуганно взглянула на него. У Ростова слезы стояли в глазах. Княжна Марья заметила это и благодарно посмотрела на Ростова тем своим лучистым взглядом, который заставлял забывать некрасивость ее лица.
– Не могу выразить, княжна, как я счастлив тем, что я случайно заехал сюда и буду в состоянии показать вам свою готовность, – сказал Ростов, вставая. – Извольте ехать, и я отвечаю вам своей честью, что ни один человек не посмеет сделать вам неприятность, ежели вы мне только позволите конвоировать вас, – и, почтительно поклонившись, как кланяются дамам царской крови, он направился к двери.
Почтительностью своего тона Ростов как будто показывал, что, несмотря на то, что он за счастье бы счел свое знакомство с нею, он не хотел пользоваться случаем ее несчастия для сближения с нею.
Княжна Марья поняла и оценила этот тон.
– Я очень, очень благодарна вам, – сказала ему княжна по французски, – но надеюсь, что все это было только недоразуменье и что никто не виноват в том. – Княжна вдруг заплакала. – Извините меня, – сказала она.
Ростов, нахмурившись, еще раз низко поклонился и вышел из комнаты.


– Ну что, мила? Нет, брат, розовая моя прелесть, и Дуняшей зовут… – Но, взглянув на лицо Ростова, Ильин замолк. Он видел, что его герой и командир находился совсем в другом строе мыслей.
Ростов злобно оглянулся на Ильина и, не отвечая ему, быстрыми шагами направился к деревне.
– Я им покажу, я им задам, разбойникам! – говорил он про себя.
Алпатыч плывущим шагом, чтобы только не бежать, рысью едва догнал Ростова.
– Какое решение изволили принять? – сказал он, догнав его.
Ростов остановился и, сжав кулаки, вдруг грозно подвинулся на Алпатыча.
– Решенье? Какое решенье? Старый хрыч! – крикнул он на него. – Ты чего смотрел? А? Мужики бунтуют, а ты не умеешь справиться? Ты сам изменник. Знаю я вас, шкуру спущу со всех… – И, как будто боясь растратить понапрасну запас своей горячности, он оставил Алпатыча и быстро пошел вперед. Алпатыч, подавив чувство оскорбления, плывущим шагом поспевал за Ростовым и продолжал сообщать ему свои соображения. Он говорил, что мужики находились в закоснелости, что в настоящую минуту было неблагоразумно противуборствовать им, не имея военной команды, что не лучше ли бы было послать прежде за командой.
– Я им дам воинскую команду… Я их попротивоборствую, – бессмысленно приговаривал Николай, задыхаясь от неразумной животной злобы и потребности излить эту злобу. Не соображая того, что будет делать, бессознательно, быстрым, решительным шагом он подвигался к толпе. И чем ближе он подвигался к ней, тем больше чувствовал Алпатыч, что неблагоразумный поступок его может произвести хорошие результаты. То же чувствовали и мужики толпы, глядя на его быструю и твердую походку и решительное, нахмуренное лицо.
После того как гусары въехали в деревню и Ростов прошел к княжне, в толпе произошло замешательство и раздор. Некоторые мужики стали говорить, что эти приехавшие были русские и как бы они не обиделись тем, что не выпускают барышню. Дрон был того же мнения; но как только он выразил его, так Карп и другие мужики напали на бывшего старосту.
– Ты мир то поедом ел сколько годов? – кричал на него Карп. – Тебе все одно! Ты кубышку выроешь, увезешь, тебе что, разори наши дома али нет?
– Сказано, порядок чтоб был, не езди никто из домов, чтобы ни синь пороха не вывозить, – вот она и вся! – кричал другой.
– Очередь на твоего сына была, а ты небось гладуха своего пожалел, – вдруг быстро заговорил маленький старичок, нападая на Дрона, – а моего Ваньку забрил. Эх, умирать будем!
– То то умирать будем!
– Я от миру не отказчик, – говорил Дрон.
– То то не отказчик, брюхо отрастил!..
Два длинные мужика говорили свое. Как только Ростов, сопутствуемый Ильиным, Лаврушкой и Алпатычем, подошел к толпе, Карп, заложив пальцы за кушак, слегка улыбаясь, вышел вперед. Дрон, напротив, зашел в задние ряды, и толпа сдвинулась плотнее.
– Эй! кто у вас староста тут? – крикнул Ростов, быстрым шагом подойдя к толпе.
– Староста то? На что вам?.. – спросил Карп. Но не успел он договорить, как шапка слетела с него и голова мотнулась набок от сильного удара.
– Шапки долой, изменники! – крикнул полнокровный голос Ростова. – Где староста? – неистовым голосом кричал он.
– Старосту, старосту кличет… Дрон Захарыч, вас, – послышались кое где торопливо покорные голоса, и шапки стали сниматься с голов.
– Нам бунтовать нельзя, мы порядки блюдем, – проговорил Карп, и несколько голосов сзади в то же мгновенье заговорили вдруг:
– Как старички пороптали, много вас начальства…
– Разговаривать?.. Бунт!.. Разбойники! Изменники! – бессмысленно, не своим голосом завопил Ростов, хватая за юрот Карпа. – Вяжи его, вяжи! – кричал он, хотя некому было вязать его, кроме Лаврушки и Алпатыча.
Лаврушка, однако, подбежал к Карпу и схватил его сзади за руки.
– Прикажете наших из под горы кликнуть? – крикнул он.
Алпатыч обратился к мужикам, вызывая двоих по именам, чтобы вязать Карпа. Мужики покорно вышли из толпы и стали распоясываться.
– Староста где? – кричал Ростов.
Дрон, с нахмуренным и бледным лицом, вышел из толпы.
– Ты староста? Вязать, Лаврушка! – кричал Ростов, как будто и это приказание не могло встретить препятствий. И действительно, еще два мужика стали вязать Дрона, который, как бы помогая им, снял с себя кушан и подал им.
– А вы все слушайте меня, – Ростов обратился к мужикам: – Сейчас марш по домам, и чтобы голоса вашего я не слыхал.
– Что ж, мы никакой обиды не делали. Мы только, значит, по глупости. Только вздор наделали… Я же сказывал, что непорядки, – послышались голоса, упрекавшие друг друга.
– Вот я же вам говорил, – сказал Алпатыч, вступая в свои права. – Нехорошо, ребята!
– Глупость наша, Яков Алпатыч, – отвечали голоса, и толпа тотчас же стала расходиться и рассыпаться по деревне.
Связанных двух мужиков повели на барский двор. Два пьяные мужика шли за ними.
– Эх, посмотрю я на тебя! – говорил один из них, обращаясь к Карпу.
– Разве можно так с господами говорить? Ты думал что?
– Дурак, – подтверждал другой, – право, дурак!
Через два часа подводы стояли на дворе богучаровского дома. Мужики оживленно выносили и укладывали на подводы господские вещи, и Дрон, по желанию княжны Марьи выпущенный из рундука, куда его заперли, стоя на дворе, распоряжался мужиками.
– Ты ее так дурно не клади, – говорил один из мужиков, высокий человек с круглым улыбающимся лицом, принимая из рук горничной шкатулку. – Она ведь тоже денег стоит. Что же ты ее так то вот бросишь или пол веревку – а она потрется. Я так не люблю. А чтоб все честно, по закону было. Вот так то под рогожку, да сенцом прикрой, вот и важно. Любо!
– Ишь книг то, книг, – сказал другой мужик, выносивший библиотечные шкафы князя Андрея. – Ты не цепляй! А грузно, ребята, книги здоровые!
– Да, писали, не гуляли! – значительно подмигнув, сказал высокий круглолицый мужик, указывая на толстые лексиконы, лежавшие сверху.

Ростов, не желая навязывать свое знакомство княжне, не пошел к ней, а остался в деревне, ожидая ее выезда. Дождавшись выезда экипажей княжны Марьи из дома, Ростов сел верхом и до пути, занятого нашими войсками, в двенадцати верстах от Богучарова, верхом провожал ее. В Янкове, на постоялом дворе, он простился с нею почтительно, в первый раз позволив себе поцеловать ее руку.
– Как вам не совестно, – краснея, отвечал он княжне Марье на выражение благодарности за ее спасенье (как она называла его поступок), – каждый становой сделал бы то же. Если бы нам только приходилось воевать с мужиками, мы бы не допустили так далеко неприятеля, – говорил он, стыдясь чего то и стараясь переменить разговор. – Я счастлив только, что имел случай познакомиться с вами. Прощайте, княжна, желаю вам счастия и утешения и желаю встретиться с вами при более счастливых условиях. Ежели вы не хотите заставить краснеть меня, пожалуйста, не благодарите.
Но княжна, если не благодарила более словами, благодарила его всем выражением своего сиявшего благодарностью и нежностью лица. Она не могла верить ему, что ей не за что благодарить его. Напротив, для нее несомненно было то, что ежели бы его не было, то она, наверное, должна была бы погибнуть и от бунтовщиков и от французов; что он, для того чтобы спасти ее, подвергал себя самым очевидным и страшным опасностям; и еще несомненнее было то, что он был человек с высокой и благородной душой, который умел понять ее положение и горе. Его добрые и честные глаза с выступившими на них слезами, в то время как она сама, заплакав, говорила с ним о своей потере, не выходили из ее воображения.
Когда она простилась с ним и осталась одна, княжна Марья вдруг почувствовала в глазах слезы, и тут уж не в первый раз ей представился странный вопрос, любит ли она его?
По дороге дальше к Москве, несмотря на то, что положение княжны было не радостно, Дуняша, ехавшая с ней в карете, не раз замечала, что княжна, высунувшись в окно кареты, чему то радостно и грустно улыбалась.
«Ну что же, ежели бы я и полюбила его? – думала княжна Марья.
Как ни стыдно ей было признаться себе, что она первая полюбила человека, который, может быть, никогда не полюбит ее, она утешала себя мыслью, что никто никогда не узнает этого и что она не будет виновата, ежели будет до конца жизни, никому не говоря о том, любить того, которого она любила в первый и в последний раз.
Иногда она вспоминала его взгляды, его участие, его слова, и ей казалось счастье не невозможным. И тогда то Дуняша замечала, что она, улыбаясь, глядела в окно кареты.
«И надо было ему приехать в Богучарово, и в эту самую минуту! – думала княжна Марья. – И надо было его сестре отказать князю Андрею! – И во всем этом княжна Марья видела волю провиденья.
Впечатление, произведенное на Ростова княжной Марьей, было очень приятное. Когда ои вспоминал про нее, ему становилось весело, и когда товарищи, узнав о бывшем с ним приключении в Богучарове, шутили ему, что он, поехав за сеном, подцепил одну из самых богатых невест в России, Ростов сердился. Он сердился именно потому, что мысль о женитьбе на приятной для него, кроткой княжне Марье с огромным состоянием не раз против его воли приходила ему в голову. Для себя лично Николай не мог желать жены лучше княжны Марьи: женитьба на ней сделала бы счастье графини – его матери, и поправила бы дела его отца; и даже – Николай чувствовал это – сделала бы счастье княжны Марьи. Но Соня? И данное слово? И от этого то Ростов сердился, когда ему шутили о княжне Болконской.


Приняв командование над армиями, Кутузов вспомнил о князе Андрее и послал ему приказание прибыть в главную квартиру.
Князь Андрей приехал в Царево Займище в тот самый день и в то самое время дня, когда Кутузов делал первый смотр войскам. Князь Андрей остановился в деревне у дома священника, у которого стоял экипаж главнокомандующего, и сел на лавочке у ворот, ожидая светлейшего, как все называли теперь Кутузова. На поле за деревней слышны были то звуки полковой музыки, то рев огромного количества голосов, кричавших «ура!новому главнокомандующему. Тут же у ворот, шагах в десяти от князя Андрея, пользуясь отсутствием князя и прекрасной погодой, стояли два денщика, курьер и дворецкий. Черноватый, обросший усами и бакенбардами, маленький гусарский подполковник подъехал к воротам и, взглянув на князя Андрея, спросил: здесь ли стоит светлейший и скоро ли он будет?
Князь Андрей сказал, что он не принадлежит к штабу светлейшего и тоже приезжий. Гусарский подполковник обратился к нарядному денщику, и денщик главнокомандующего сказал ему с той особенной презрительностью, с которой говорят денщики главнокомандующих с офицерами:
– Что, светлейший? Должно быть, сейчас будет. Вам что?
Гусарский подполковник усмехнулся в усы на тон денщика, слез с лошади, отдал ее вестовому и подошел к Болконскому, слегка поклонившись ему. Болконский посторонился на лавке. Гусарский подполковник сел подле него.
– Тоже дожидаетесь главнокомандующего? – заговорил гусарский подполковник. – Говог'ят, всем доступен, слава богу. А то с колбасниками беда! Недаг'ом Ег'молов в немцы пг'осился. Тепег'ь авось и г'усским говог'ить можно будет. А то чег'т знает что делали. Все отступали, все отступали. Вы делали поход? – спросил он.
– Имел удовольствие, – отвечал князь Андрей, – не только участвовать в отступлении, но и потерять в этом отступлении все, что имел дорогого, не говоря об именьях и родном доме… отца, который умер с горя. Я смоленский.
– А?.. Вы князь Болконский? Очень г'ад познакомиться: подполковник Денисов, более известный под именем Васьки, – сказал Денисов, пожимая руку князя Андрея и с особенно добрым вниманием вглядываясь в лицо Болконского. – Да, я слышал, – сказал он с сочувствием и, помолчав немного, продолжал: – Вот и скифская война. Это все хог'ошо, только не для тех, кто своими боками отдувается. А вы – князь Андг'ей Болконский? – Он покачал головой. – Очень г'ад, князь, очень г'ад познакомиться, – прибавил он опять с грустной улыбкой, пожимая ему руку.
Князь Андрей знал Денисова по рассказам Наташи о ее первом женихе. Это воспоминанье и сладко и больно перенесло его теперь к тем болезненным ощущениям, о которых он последнее время давно уже не думал, но которые все таки были в его душе. В последнее время столько других и таких серьезных впечатлений, как оставление Смоленска, его приезд в Лысые Горы, недавнее известно о смерти отца, – столько ощущений было испытано им, что эти воспоминания уже давно не приходили ему и, когда пришли, далеко не подействовали на него с прежней силой. И для Денисова тот ряд воспоминаний, которые вызвало имя Болконского, было далекое, поэтическое прошедшее, когда он, после ужина и пения Наташи, сам не зная как, сделал предложение пятнадцатилетней девочке. Он улыбнулся воспоминаниям того времени и своей любви к Наташе и тотчас же перешел к тому, что страстно и исключительно теперь занимало его. Это был план кампании, который он придумал, служа во время отступления на аванпостах. Он представлял этот план Барклаю де Толли и теперь намерен был представить его Кутузову. План основывался на том, что операционная линия французов слишком растянута и что вместо того, или вместе с тем, чтобы действовать с фронта, загораживая дорогу французам, нужно было действовать на их сообщения. Он начал разъяснять свой план князю Андрею.
– Они не могут удержать всей этой линии. Это невозможно, я отвечаю, что пг'ог'ву их; дайте мне пятьсот человек, я г'азог'ву их, это вег'но! Одна система – паг'тизанская.
Денисов встал и, делая жесты, излагал свой план Болконскому. В средине его изложения крики армии, более нескладные, более распространенные и сливающиеся с музыкой и песнями, послышались на месте смотра. На деревне послышался топот и крики.
– Сам едет, – крикнул казак, стоявший у ворот, – едет! Болконский и Денисов подвинулись к воротам, у которых стояла кучка солдат (почетный караул), и увидали подвигавшегося по улице Кутузова, верхом на невысокой гнедой лошадке. Огромная свита генералов ехала за ним. Барклай ехал почти рядом; толпа офицеров бежала за ними и вокруг них и кричала «ура!».
Вперед его во двор проскакали адъютанты. Кутузов, нетерпеливо подталкивая свою лошадь, плывшую иноходью под его тяжестью, и беспрестанно кивая головой, прикладывал руку к бедой кавалергардской (с красным околышем и без козырька) фуражке, которая была на нем. Подъехав к почетному караулу молодцов гренадеров, большей частью кавалеров, отдававших ему честь, он с минуту молча, внимательно посмотрел на них начальническим упорным взглядом и обернулся к толпе генералов и офицеров, стоявших вокруг него. Лицо его вдруг приняло тонкое выражение; он вздернул плечами с жестом недоумения.
– И с такими молодцами всё отступать и отступать! – сказал он. – Ну, до свиданья, генерал, – прибавил он и тронул лошадь в ворота мимо князя Андрея и Денисова.
– Ура! ура! ура! – кричали сзади его.
С тех пор как не видал его князь Андрей, Кутузов еще потолстел, обрюзг и оплыл жиром. Но знакомые ему белый глаз, и рана, и выражение усталости в его лице и фигуре были те же. Он был одет в мундирный сюртук (плеть на тонком ремне висела через плечо) и в белой кавалергардской фуражке. Он, тяжело расплываясь и раскачиваясь, сидел на своей бодрой лошадке.
– Фю… фю… фю… – засвистал он чуть слышно, въезжая на двор. На лице его выражалась радость успокоения человека, намеревающегося отдохнуть после представительства. Он вынул левую ногу из стремени, повалившись всем телом и поморщившись от усилия, с трудом занес ее на седло, облокотился коленкой, крякнул и спустился на руки к казакам и адъютантам, поддерживавшим его.
Он оправился, оглянулся своими сощуренными глазами и, взглянув на князя Андрея, видимо, не узнав его, зашагал своей ныряющей походкой к крыльцу.
– Фю… фю… фю, – просвистал он и опять оглянулся на князя Андрея. Впечатление лица князя Андрея только после нескольких секунд (как это часто бывает у стариков) связалось с воспоминанием о его личности.
– А, здравствуй, князь, здравствуй, голубчик, пойдем… – устало проговорил он, оглядываясь, и тяжело вошел на скрипящее под его тяжестью крыльцо. Он расстегнулся и сел на лавочку, стоявшую на крыльце.
– Ну, что отец?
– Вчера получил известие о его кончине, – коротко сказал князь Андрей.
Кутузов испуганно открытыми глазами посмотрел на князя Андрея, потом снял фуражку и перекрестился: «Царство ему небесное! Да будет воля божия над всеми нами!Он тяжело, всей грудью вздохнул и помолчал. „Я его любил и уважал и сочувствую тебе всей душой“. Он обнял князя Андрея, прижал его к своей жирной груди и долго не отпускал от себя. Когда он отпустил его, князь Андрей увидал, что расплывшие губы Кутузова дрожали и на глазах были слезы. Он вздохнул и взялся обеими руками за лавку, чтобы встать.
– Пойдем, пойдем ко мне, поговорим, – сказал он; но в это время Денисов, так же мало робевший перед начальством, как и перед неприятелем, несмотря на то, что адъютанты у крыльца сердитым шепотом останавливали его, смело, стуча шпорами по ступенькам, вошел на крыльцо. Кутузов, оставив руки упертыми на лавку, недовольно смотрел на Денисова. Денисов, назвав себя, объявил, что имеет сообщить его светлости дело большой важности для блага отечества. Кутузов усталым взглядом стал смотреть на Денисова и досадливым жестом, приняв руки и сложив их на животе, повторил: «Для блага отечества? Ну что такое? Говори». Денисов покраснел, как девушка (так странно было видеть краску на этом усатом, старом и пьяном лице), и смело начал излагать свой план разрезания операционной линии неприятеля между Смоленском и Вязьмой. Денисов жил в этих краях и знал хорошо местность. План его казался несомненно хорошим, в особенности по той силе убеждения, которая была в его словах. Кутузов смотрел себе на ноги и изредка оглядывался на двор соседней избы, как будто он ждал чего то неприятного оттуда. Из избы, на которую он смотрел, действительно во время речи Денисова показался генерал с портфелем под мышкой.
– Что? – в середине изложения Денисова проговорил Кутузов. – Уже готовы?
– Готов, ваша светлость, – сказал генерал. Кутузов покачал головой, как бы говоря: «Как это все успеть одному человеку», и продолжал слушать Денисова.
– Даю честное благородное слово гусского офицег'а, – говорил Денисов, – что я г'азог'ву сообщения Наполеона.
– Тебе Кирилл Андреевич Денисов, обер интендант, как приходится? – перебил его Кутузов.
– Дядя г'одной, ваша светлость.
– О! приятели были, – весело сказал Кутузов. – Хорошо, хорошо, голубчик, оставайся тут при штабе, завтра поговорим. – Кивнув головой Денисову, он отвернулся и протянул руку к бумагам, которые принес ему Коновницын.
– Не угодно ли вашей светлости пожаловать в комнаты, – недовольным голосом сказал дежурный генерал, – необходимо рассмотреть планы и подписать некоторые бумаги. – Вышедший из двери адъютант доложил, что в квартире все было готово. Но Кутузову, видимо, хотелось войти в комнаты уже свободным. Он поморщился…
– Нет, вели подать, голубчик, сюда столик, я тут посмотрю, – сказал он. – Ты не уходи, – прибавил он, обращаясь к князю Андрею. Князь Андрей остался на крыльце, слушая дежурного генерала.
Во время доклада за входной дверью князь Андрей слышал женское шептанье и хрустение женского шелкового платья. Несколько раз, взглянув по тому направлению, он замечал за дверью, в розовом платье и лиловом шелковом платке на голове, полную, румяную и красивую женщину с блюдом, которая, очевидно, ожидала входа влавввквмандующего. Адъютант Кутузова шепотом объяснил князю Андрею, что это была хозяйка дома, попадья, которая намеревалась подать хлеб соль его светлости. Муж ее встретил светлейшего с крестом в церкви, она дома… «Очень хорошенькая», – прибавил адъютант с улыбкой. Кутузов оглянулся на эти слова. Кутузов слушал доклад дежурного генерала (главным предметом которого была критика позиции при Цареве Займище) так же, как он слушал Денисова, так же, как он слушал семь лет тому назад прения Аустерлицкого военного совета. Он, очевидно, слушал только оттого, что у него были уши, которые, несмотря на то, что в одном из них был морской канат, не могли не слышать; но очевидно было, что ничто из того, что мог сказать ему дежурный генерал, не могло не только удивить или заинтересовать его, но что он знал вперед все, что ему скажут, и слушал все это только потому, что надо прослушать, как надо прослушать поющийся молебен. Все, что говорил Денисов, было дельно и умно. То, что говорил дежурный генерал, было еще дельнее и умнее, но очевидно было, что Кутузов презирал и знание и ум и знал что то другое, что должно было решить дело, – что то другое, независимое от ума и знания. Князь Андрей внимательно следил за выражением лица главнокомандующего, и единственное выражение, которое он мог заметить в нем, было выражение скуки, любопытства к тому, что такое означал женский шепот за дверью, и желание соблюсти приличие. Очевидно было, что Кутузов презирал ум, и знание, и даже патриотическое чувство, которое выказывал Денисов, но презирал не умом, не чувством, не знанием (потому что он и не старался выказывать их), а он презирал их чем то другим. Он презирал их своей старостью, своею опытностью жизни. Одно распоряжение, которое от себя в этот доклад сделал Кутузов, откосилось до мародерства русских войск. Дежурный редерал в конце доклада представил светлейшему к подписи бумагу о взысканий с армейских начальников по прошению помещика за скошенный зеленый овес.
Кутузов зачмокал губами и закачал головой, выслушав это дело.
– В печку… в огонь! И раз навсегда тебе говорю, голубчик, – сказал он, – все эти дела в огонь. Пуская косят хлеба и жгут дрова на здоровье. Я этого не приказываю и не позволяю, но и взыскивать не могу. Без этого нельзя. Дрова рубят – щепки летят. – Он взглянул еще раз на бумагу. – О, аккуратность немецкая! – проговорил он, качая головой.


– Ну, теперь все, – сказал Кутузов, подписывая последнюю бумагу, и, тяжело поднявшись и расправляя складки своей белой пухлой шеи, с повеселевшим лицом направился к двери.
Попадья, с бросившеюся кровью в лицо, схватилась за блюдо, которое, несмотря на то, что она так долго приготовлялась, она все таки не успела подать вовремя. И с низким поклоном она поднесла его Кутузову.
Глаза Кутузова прищурились; он улыбнулся, взял рукой ее за подбородок и сказал:
– И красавица какая! Спасибо, голубушка!
Он достал из кармана шаровар несколько золотых и положил ей на блюдо.
– Ну что, как живешь? – сказал Кутузов, направляясь к отведенной для него комнате. Попадья, улыбаясь ямочками на румяном лице, прошла за ним в горницу. Адъютант вышел к князю Андрею на крыльцо и приглашал его завтракать; через полчаса князя Андрея позвали опять к Кутузову. Кутузов лежал на кресле в том же расстегнутом сюртуке. Он держал в руке французскую книгу и при входе князя Андрея, заложив ее ножом, свернул. Это был «Les chevaliers du Cygne», сочинение madame de Genlis [«Рыцари Лебедя», мадам де Жанлис], как увидал князь Андрей по обертке.
– Ну садись, садись тут, поговорим, – сказал Кутузов. – Грустно, очень грустно. Но помни, дружок, что я тебе отец, другой отец… – Князь Андрей рассказал Кутузову все, что он знал о кончине своего отца, и о том, что он видел в Лысых Горах, проезжая через них.
– До чего… до чего довели! – проговорил вдруг Кутузов взволнованным голосом, очевидно, ясно представив себе, из рассказа князя Андрея, положение, в котором находилась Россия. – Дай срок, дай срок, – прибавил он с злобным выражением лица и, очевидно, не желая продолжать этого волновавшего его разговора, сказал: – Я тебя вызвал, чтоб оставить при себе.
– Благодарю вашу светлость, – отвечал князь Андрей, – но я боюсь, что не гожусь больше для штабов, – сказал он с улыбкой, которую Кутузов заметил. Кутузов вопросительно посмотрел на него. – А главное, – прибавил князь Андрей, – я привык к полку, полюбил офицеров, и люди меня, кажется, полюбили. Мне бы жалко было оставить полк. Ежели я отказываюсь от чести быть при вас, то поверьте…
Умное, доброе и вместе с тем тонко насмешливое выражение светилось на пухлом лице Кутузова. Он перебил Болконского:
– Жалею, ты бы мне нужен был; но ты прав, ты прав. Нам не сюда люди нужны. Советчиков всегда много, а людей нет. Не такие бы полки были, если бы все советчики служили там в полках, как ты. Я тебя с Аустерлица помню… Помню, помню, с знаменем помню, – сказал Кутузов, и радостная краска бросилась в лицо князя Андрея при этом воспоминании. Кутузов притянул его за руку, подставляя ему щеку, и опять князь Андрей на глазах старика увидал слезы. Хотя князь Андрей и знал, что Кутузов был слаб на слезы и что он теперь особенно ласкает его и жалеет вследствие желания выказать сочувствие к его потере, но князю Андрею и радостно и лестно было это воспоминание об Аустерлице.
– Иди с богом своей дорогой. Я знаю, твоя дорога – это дорога чести. – Он помолчал. – Я жалел о тебе в Букареште: мне послать надо было. – И, переменив разговор, Кутузов начал говорить о турецкой войне и заключенном мире. – Да, немало упрекали меня, – сказал Кутузов, – и за войну и за мир… а все пришло вовремя. Tout vient a point a celui qui sait attendre. [Все приходит вовремя для того, кто умеет ждать.] A и там советчиков не меньше было, чем здесь… – продолжал он, возвращаясь к советчикам, которые, видимо, занимали его. – Ох, советчики, советчики! – сказал он. Если бы всех слушать, мы бы там, в Турции, и мира не заключили, да и войны бы не кончили. Всё поскорее, а скорое на долгое выходит. Если бы Каменский не умер, он бы пропал. Он с тридцатью тысячами штурмовал крепости. Взять крепость не трудно, трудно кампанию выиграть. А для этого не нужно штурмовать и атаковать, а нужно терпение и время. Каменский на Рущук солдат послал, а я их одних (терпение и время) посылал и взял больше крепостей, чем Каменский, и лошадиное мясо турок есть заставил. – Он покачал головой. – И французы тоже будут! Верь моему слову, – воодушевляясь, проговорил Кутузов, ударяя себя в грудь, – будут у меня лошадиное мясо есть! – И опять глаза его залоснились слезами.
– Однако до лжно же будет принять сражение? – сказал князь Андрей.
– До лжно будет, если все этого захотят, нечего делать… А ведь, голубчик: нет сильнее тех двух воинов, терпение и время; те всё сделают, да советчики n'entendent pas de cette oreille, voila le mal. [этим ухом не слышат, – вот что плохо.] Одни хотят, другие не хотят. Что ж делать? – спросил он, видимо, ожидая ответа. – Да, что ты велишь делать? – повторил он, и глаза его блестели глубоким, умным выражением. – Я тебе скажу, что делать, – проговорил он, так как князь Андрей все таки не отвечал. – Я тебе скажу, что делать и что я делаю. Dans le doute, mon cher, – он помолчал, – abstiens toi, [В сомнении, мой милый, воздерживайся.] – выговорил он с расстановкой.
– Ну, прощай, дружок; помни, что я всей душой несу с тобой твою потерю и что я тебе не светлейший, не князь и не главнокомандующий, а я тебе отец. Ежели что нужно, прямо ко мне. Прощай, голубчик. – Он опять обнял и поцеловал его. И еще князь Андрей не успел выйти в дверь, как Кутузов успокоительно вздохнул и взялся опять за неконченный роман мадам Жанлис «Les chevaliers du Cygne».
Как и отчего это случилось, князь Андрей не мог бы никак объяснить; но после этого свидания с Кутузовым он вернулся к своему полку успокоенный насчет общего хода дела и насчет того, кому оно вверено было. Чем больше он видел отсутствие всего личного в этом старике, в котором оставались как будто одни привычки страстей и вместо ума (группирующего события и делающего выводы) одна способность спокойного созерцания хода событий, тем более он был спокоен за то, что все будет так, как должно быть. «У него не будет ничего своего. Он ничего не придумает, ничего не предпримет, – думал князь Андрей, – но он все выслушает, все запомнит, все поставит на свое место, ничему полезному не помешает и ничего вредного не позволит. Он понимает, что есть что то сильнее и значительнее его воли, – это неизбежный ход событий, и он умеет видеть их, умеет понимать их значение и, ввиду этого значения, умеет отрекаться от участия в этих событиях, от своей личной волн, направленной на другое. А главное, – думал князь Андрей, – почему веришь ему, – это то, что он русский, несмотря на роман Жанлис и французские поговорки; это то, что голос его задрожал, когда он сказал: „До чего довели!“, и что он захлипал, говоря о том, что он „заставит их есть лошадиное мясо“. На этом же чувстве, которое более или менее смутно испытывали все, и основано было то единомыслие и общее одобрение, которое сопутствовало народному, противному придворным соображениям, избранию Кутузова в главнокомандующие.


После отъезда государя из Москвы московская жизнь потекла прежним, обычным порядком, и течение этой жизни было так обычно, что трудно было вспомнить о бывших днях патриотического восторга и увлечения, и трудно было верить, что действительно Россия в опасности и что члены Английского клуба суть вместе с тем и сыны отечества, готовые для него на всякую жертву. Одно, что напоминало о бывшем во время пребывания государя в Москве общем восторженно патриотическом настроении, было требование пожертвований людьми и деньгами, которые, как скоро они были сделаны, облеклись в законную, официальную форму и казались неизбежны.
С приближением неприятеля к Москве взгляд москвичей на свое положение не только не делался серьезнее, но, напротив, еще легкомысленнее, как это всегда бывает с людьми, которые видят приближающуюся большую опасность. При приближении опасности всегда два голоса одинаково сильно говорят в душе человека: один весьма разумно говорит о том, чтобы человек обдумал самое свойство опасности и средства для избавления от нее; другой еще разумнее говорит, что слишком тяжело и мучительно думать об опасности, тогда как предвидеть все и спастись от общего хода дела не во власти человека, и потому лучше отвернуться от тяжелого, до тех пор пока оно не наступило, и думать о приятном. В одиночестве человек большею частью отдается первому голосу, в обществе, напротив, – второму. Так было и теперь с жителями Москвы. Давно так не веселились в Москве, как этот год.
Растопчинские афишки с изображением вверху питейного дома, целовальника и московского мещанина Карпушки Чигирина, который, быв в ратниках и выпив лишний крючок на тычке, услыхал, будто Бонапарт хочет идти на Москву, рассердился, разругал скверными словами всех французов, вышел из питейного дома и заговорил под орлом собравшемуся народу, читались и обсуживались наравне с последним буриме Василия Львовича Пушкина.
В клубе, в угловой комнате, собирались читать эти афиши, и некоторым нравилось, как Карпушка подтрунивал над французами, говоря, что они от капусты раздуются, от каши перелопаются, от щей задохнутся, что они все карлики и что их троих одна баба вилами закинет. Некоторые не одобряли этого тона и говорила, что это пошло и глупо. Рассказывали о том, что французов и даже всех иностранцев Растопчин выслал из Москвы, что между ними шпионы и агенты Наполеона; но рассказывали это преимущественно для того, чтобы при этом случае передать остроумные слова, сказанные Растопчиным при их отправлении. Иностранцев отправляли на барке в Нижний, и Растопчин сказал им: «Rentrez en vous meme, entrez dans la barque et n'en faites pas une barque ne Charon». [войдите сами в себя и в эту лодку и постарайтесь, чтобы эта лодка не сделалась для вас лодкой Харона.] Рассказывали, что уже выслали из Москвы все присутственные места, и тут же прибавляли шутку Шиншина, что за это одно Москва должна быть благодарна Наполеону. Рассказывали, что Мамонову его полк будет стоить восемьсот тысяч, что Безухов еще больше затратил на своих ратников, но что лучше всего в поступке Безухова то, что он сам оденется в мундир и поедет верхом перед полком и ничего не будет брать за места с тех, которые будут смотреть на него.
– Вы никому не делаете милости, – сказала Жюли Друбецкая, собирая и прижимая кучку нащипанной корпии тонкими пальцами, покрытыми кольцами.
Жюли собиралась на другой день уезжать из Москвы и делала прощальный вечер.
– Безухов est ridicule [смешон], но он так добр, так мил. Что за удовольствие быть так caustique [злоязычным]?
– Штраф! – сказал молодой человек в ополченском мундире, которого Жюли называла «mon chevalier» [мой рыцарь] и который с нею вместе ехал в Нижний.
В обществе Жюли, как и во многих обществах Москвы, было положено говорить только по русски, и те, которые ошибались, говоря французские слова, платили штраф в пользу комитета пожертвований.
– Другой штраф за галлицизм, – сказал русский писатель, бывший в гостиной. – «Удовольствие быть не по русски.
– Вы никому не делаете милости, – продолжала Жюли к ополченцу, не обращая внимания на замечание сочинителя. – За caustique виновата, – сказала она, – и плачу, но за удовольствие сказать вам правду я готова еще заплатить; за галлицизмы не отвечаю, – обратилась она к сочинителю: – у меня нет ни денег, ни времени, как у князя Голицына, взять учителя и учиться по русски. А вот и он, – сказала Жюли. – Quand on… [Когда.] Нет, нет, – обратилась она к ополченцу, – не поймаете. Когда говорят про солнце – видят его лучи, – сказала хозяйка, любезно улыбаясь Пьеру. – Мы только говорили о вас, – с свойственной светским женщинам свободой лжи сказала Жюли. – Мы говорили, что ваш полк, верно, будет лучше мамоновского.
– Ах, не говорите мне про мой полк, – отвечал Пьер, целуя руку хозяйке и садясь подле нее. – Он мне так надоел!
– Вы ведь, верно, сами будете командовать им? – сказала Жюли, хитро и насмешливо переглянувшись с ополченцем.
Ополченец в присутствии Пьера был уже не так caustique, и в лице его выразилось недоуменье к тому, что означала улыбка Жюли. Несмотря на свою рассеянность и добродушие, личность Пьера прекращала тотчас же всякие попытки на насмешку в его присутствии.
– Нет, – смеясь, отвечал Пьер, оглядывая свое большое, толстое тело. – В меня слишком легко попасть французам, да и я боюсь, что не влезу на лошадь…
В числе перебираемых лиц для предмета разговора общество Жюли попало на Ростовых.
– Очень, говорят, плохи дела их, – сказала Жюли. – И он так бестолков – сам граф. Разумовские хотели купить его дом и подмосковную, и все это тянется. Он дорожится.
– Нет, кажется, на днях состоится продажа, – сказал кто то. – Хотя теперь и безумно покупать что нибудь в Москве.
– Отчего? – сказала Жюли. – Неужели вы думаете, что есть опасность для Москвы?
– Отчего же вы едете?
– Я? Вот странно. Я еду, потому… ну потому, что все едут, и потом я не Иоанна д'Арк и не амазонка.
– Ну, да, да, дайте мне еще тряпочек.
– Ежели он сумеет повести дела, он может заплатить все долги, – продолжал ополченец про Ростова.
– Добрый старик, но очень pauvre sire [плох]. И зачем они живут тут так долго? Они давно хотели ехать в деревню. Натали, кажется, здорова теперь? – хитро улыбаясь, спросила Жюли у Пьера.
– Они ждут меньшого сына, – сказал Пьер. – Он поступил в казаки Оболенского и поехал в Белую Церковь. Там формируется полк. А теперь они перевели его в мой полк и ждут каждый день. Граф давно хотел ехать, но графиня ни за что не согласна выехать из Москвы, пока не приедет сын.
– Я их третьего дня видела у Архаровых. Натали опять похорошела и повеселела. Она пела один романс. Как все легко проходит у некоторых людей!
– Что проходит? – недовольно спросил Пьер. Жюли улыбнулась.
– Вы знаете, граф, что такие рыцари, как вы, бывают только в романах madame Suza.
– Какой рыцарь? Отчего? – краснея, спросил Пьер.
– Ну, полноте, милый граф, c'est la fable de tout Moscou. Je vous admire, ma parole d'honneur. [это вся Москва знает. Право, я вам удивляюсь.]
– Штраф! Штраф! – сказал ополченец.
– Ну, хорошо. Нельзя говорить, как скучно!
– Qu'est ce qui est la fable de tout Moscou? [Что знает вся Москва?] – вставая, сказал сердито Пьер.
– Полноте, граф. Вы знаете!
– Ничего не знаю, – сказал Пьер.
– Я знаю, что вы дружны были с Натали, и потому… Нет, я всегда дружнее с Верой. Cette chere Vera! [Эта милая Вера!]
– Non, madame, [Нет, сударыня.] – продолжал Пьер недовольным тоном. – Я вовсе не взял на себя роль рыцаря Ростовой, и я уже почти месяц не был у них. Но я не понимаю жестокость…
– Qui s'excuse – s'accuse, [Кто извиняется, тот обвиняет себя.] – улыбаясь и махая корпией, говорила Жюли и, чтобы за ней осталось последнее слово, сейчас же переменила разговор. – Каково, я нынче узнала: бедная Мари Волконская приехала вчера в Москву. Вы слышали, она потеряла отца?
– Неужели! Где она? Я бы очень желал увидать ее, – сказал Пьер.
– Я вчера провела с ней вечер. Она нынче или завтра утром едет в подмосковную с племянником.
– Ну что она, как? – сказал Пьер.
– Ничего, грустна. Но знаете, кто ее спас? Это целый роман. Nicolas Ростов. Ее окружили, хотели убить, ранили ее людей. Он бросился и спас ее…
– Еще роман, – сказал ополченец. – Решительно это общее бегство сделано, чтобы все старые невесты шли замуж. Catiche – одна, княжна Болконская – другая.
– Вы знаете, что я в самом деле думаю, что она un petit peu amoureuse du jeune homme. [немножечко влюблена в молодого человека.]
– Штраф! Штраф! Штраф!
– Но как же это по русски сказать?..


Когда Пьер вернулся домой, ему подали две принесенные в этот день афиши Растопчина.
В первой говорилось о том, что слух, будто графом Растопчиным запрещен выезд из Москвы, – несправедлив и что, напротив, граф Растопчин рад, что из Москвы уезжают барыни и купеческие жены. «Меньше страху, меньше новостей, – говорилось в афише, – но я жизнью отвечаю, что злодей в Москве не будет». Эти слова в первый раз ясно ыоказали Пьеру, что французы будут в Москве. Во второй афише говорилось, что главная квартира наша в Вязьме, что граф Витгснштейн победил французов, но что так как многие жители желают вооружиться, то для них есть приготовленное в арсенале оружие: сабли, пистолеты, ружья, которые жители могут получать по дешевой цене. Тон афиш был уже не такой шутливый, как в прежних чигиринских разговорах. Пьер задумался над этими афишами. Очевидно, та страшная грозовая туча, которую он призывал всеми силами своей души и которая вместе с тем возбуждала в нем невольный ужас, – очевидно, туча эта приближалась.
«Поступить в военную службу и ехать в армию или дожидаться? – в сотый раз задавал себе Пьер этот вопрос. Он взял колоду карт, лежавших у него на столе, и стал делать пасьянс.
– Ежели выйдет этот пасьянс, – говорил он сам себе, смешав колоду, держа ее в руке и глядя вверх, – ежели выйдет, то значит… что значит?.. – Он не успел решить, что значит, как за дверью кабинета послышался голос старшей княжны, спрашивающей, можно ли войти.
– Тогда будет значить, что я должен ехать в армию, – договорил себе Пьер. – Войдите, войдите, – прибавил он, обращаясь к княжие.
(Одна старшая княжна, с длинной талией и окаменелым лидом, продолжала жить в доме Пьера; две меньшие вышли замуж.)
– Простите, mon cousin, что я пришла к вам, – сказала она укоризненно взволнованным голосом. – Ведь надо наконец на что нибудь решиться! Что ж это будет такое? Все выехали из Москвы, и народ бунтует. Что ж мы остаемся?
– Напротив, все, кажется, благополучно, ma cousine, – сказал Пьер с тою привычкой шутливости, которую Пьер, всегда конфузно переносивший свою роль благодетеля перед княжною, усвоил себе в отношении к ней.
– Да, это благополучно… хорошо благополучие! Мне нынче Варвара Ивановна порассказала, как войска наши отличаются. Уж точно можно чести приписать. Да и народ совсем взбунтовался, слушать перестают; девка моя и та грубить стала. Этак скоро и нас бить станут. По улицам ходить нельзя. А главное, нынче завтра французы будут, что ж нам ждать! Я об одном прошу, mon cousin, – сказала княжна, – прикажите свезти меня в Петербург: какая я ни есть, а я под бонапартовской властью жить не могу.
– Да полноте, ma cousine, откуда вы почерпаете ваши сведения? Напротив…
– Я вашему Наполеону не покорюсь. Другие как хотят… Ежели вы не хотите этого сделать…
– Да я сделаю, я сейчас прикажу.
Княжне, видимо, досадно было, что не на кого было сердиться. Она, что то шепча, присела на стул.
– Но вам это неправильно доносят, – сказал Пьер. – В городе все тихо, и опасности никакой нет. Вот я сейчас читал… – Пьер показал княжне афишки. – Граф пишет, что он жизнью отвечает, что неприятель не будет в Москве.
– Ах, этот ваш граф, – с злобой заговорила княжна, – это лицемер, злодей, который сам настроил народ бунтовать. Разве не он писал в этих дурацких афишах, что какой бы там ни был, тащи его за хохол на съезжую (и как глупо)! Кто возьмет, говорит, тому и честь и слава. Вот и долюбезничался. Варвара Ивановна говорила, что чуть не убил народ ее за то, что она по французски заговорила…
– Да ведь это так… Вы всё к сердцу очень принимаете, – сказал Пьер и стал раскладывать пасьянс.
Несмотря на то, что пасьянс сошелся, Пьер не поехал в армию, а остался в опустевшей Москве, все в той же тревоге, нерешимости, в страхе и вместе в радости ожидая чего то ужасного.
На другой день княжна к вечеру уехала, и к Пьеру приехал его главноуправляющий с известием, что требуемых им денег для обмундирования полка нельзя достать, ежели не продать одно имение. Главноуправляющий вообще представлял Пьеру, что все эти затеи полка должны были разорить его. Пьер с трудом скрывал улыбку, слушая слова управляющего.
– Ну, продайте, – говорил он. – Что ж делать, я не могу отказаться теперь!
Чем хуже было положение всяких дел, и в особенности его дел, тем Пьеру было приятнее, тем очевиднее было, что катастрофа, которой он ждал, приближается. Уже никого почти из знакомых Пьера не было в городе. Жюли уехала, княжна Марья уехала. Из близких знакомых одни Ростовы оставались; но к ним Пьер не ездил.
В этот день Пьер, для того чтобы развлечься, поехал в село Воронцово смотреть большой воздушный шар, который строился Леппихом для погибели врага, и пробный шар, который должен был быть пущен завтра. Шар этот был еще не готов; но, как узнал Пьер, он строился по желанию государя. Государь писал графу Растопчину об этом шаре следующее:
«Aussitot que Leppich sera pret, composez lui un equipage pour sa nacelle d'hommes surs et intelligents et depechez un courrier au general Koutousoff pour l'en prevenir. Je l'ai instruit de la chose.
Recommandez, je vous prie, a Leppich d'etre bien attentif sur l'endroit ou il descendra la premiere fois, pour ne pas se tromper et ne pas tomber dans les mains de l'ennemi. Il est indispensable qu'il combine ses mouvements avec le general en chef».
[Только что Леппих будет готов, составьте экипаж для его лодки из верных и умных людей и пошлите курьера к генералу Кутузову, чтобы предупредить его.