Что такое код wvsprinf

Содержание

Что такое код wvsprinf

Writes formatted data to the specified buffer. Any arguments are converted and copied to the output buffer according to the corresponding format specification in the format string. The function appends a terminating null character to the characters it writes, but the return value does not include the terminating null character in its character count.

Syntax

Parameters

Type: LPTSTR

The buffer that is to receive the formatted output. The maximum size of the buffer is 1,024 bytes.

Type: LPCTSTR

The format-control specifications. In addition to ordinary ASCII characters, a format specification for each argument appears in this string. For more information about the format specification, see the Remarks section.

One or more optional arguments. The number and type of argument parameters depend on the corresponding format-control specifications in the lpFmt parameter.

Return value

Type: int

If the function succeeds, the return value is the number of characters stored in the output buffer, not counting the terminating null character.

If the function fails, the return value is less than the length of the expected output. To get extended error information, call GetLastError.

Security Considerations

Using this function incorrectly can compromise the security of your application. The string returned in lpOut is not guaranteed to be null-terminated. Also, avoid the %s format — it can lead to a buffer overrun. If an access violation occurs it causes a denial of service against your application. In the worse case, an attacker can inject executable code. Consider using one of the following alternatives: StringCbPrintf, StringCbPrintfEx, StringCbVPrintf, StringCbVPrintfEx, StringCchPrintf, StringCchPrintfEx, StringCchVPrintf, or StringCchVPrintfEx.

Remarks

The format-control string contains format specifications that determine the output format for the arguments following the lpFmt parameter. Format specifications, discussed below, always begin with a percent sign (%). If a percent sign is followed by a character that has no meaning as a format field, the character is not formatted (for example, %% produces a single percent-sign character).

The format-control string is read from left to right. When the first format specification (if any) is encountered, it causes the value of the first argument after the format-control string to be converted and copied to the output buffer according to the format specification. The second format specification causes the second argument to be converted and copied, and so on. If there are more arguments than format specifications, the extra arguments are ignored. If there are not enough arguments for all of the format specifications, the results are undefined.

A format specification has the following form:

%[][#][][width][.precision]type

Each field is a single character or a number signifying a particular format option. The type characters that appear after the last optional format field determine whether the associated argument is interpreted as a character, a string, or a number. The simplest format specification contains only the percent sign and a type character (for example, %s). The optional fields control other aspects of the formatting. Following are the optional and required fields and their meanings.

Pad the output with blanks or zeros to the right to fill the field width, justifying output to the left. If this field is omitted, the output is padded to the left, justifying it to the right.

Prefix hexadecimal values with 0x (lowercase) or 0X (uppercase).

Pad the output value with zeros to fill the field width. If this field is omitted, the output value is padded with blank spaces.

Copy the specified minimum number of characters to the output buffer. The width field is a nonnegative integer. The width specification never causes a value to be truncated; if the number of characters in the output value is greater than the specified width, or if the width field is not present, all characters of the value are printed, subject to the precision specification.

For numbers, copy the specified minimum number of digits to the output buffer. If the number of digits in the argument is less than the specified precision, the output value is padded on the left with zeros. The value is not truncated when the number of digits exceeds the specified precision. If the specified precision is 0 or omitted entirely, or if the period (.) appears without a number following it, the precision is set to 1.

For strings, copy the specified maximum number of characters to the output buffer.

Output the corresponding argument as a character, a string, or a number. This field can be any of the following values.

Single character. This value is interpreted as type WCHAR if the calling application defines Unicode and as type __wchar_t otherwise.

Single character. This value is interpreted as type __wchar_t if the calling application defines Unicode and as type WCHAR otherwise.

Signed decimal integer. This value is equivalent to i .

Single character. The wsprintf function ignores character arguments with a numeric value of zero. This value is always interpreted as type __wchar_t, even when the calling application defines Unicode.

Signed short integer argument.

String. This value is always interpreted as type LPSTR, even when the calling application defines Unicode.

Unsigned short integer.

Signed decimal integer. This value is equivalent to d .

64-bit unsigned hexadecimal integer in lowercase or uppercase on 64-bit platforms, 32-bit unsigned hexadecimal integer in lowercase or uppercase on 32-bit platforms.

Single character. The wsprintf function ignores character arguments with a numeric value of zero. This value is always interpreted as type WCHAR, even when the calling application does not define Unicode.

Long signed integer. This value is equivalent to li .

Long signed integer. This value is equivalent to ld .

String. This value is always interpreted as type LPWSTR, even when the calling application does not define Unicode. This value is equivalent to ws .

Long unsigned integer.

Long unsigned hexadecimal integer in lowercase or uppercase.

Pointer. The address is printed using hexadecimal.

String. This value is interpreted as type LPWSTR when the calling application defines Unicode and as type LPSTR otherwise.

String. This value is interpreted as type LPSTR when the calling application defines Unicode and as type LPWSTR otherwise.

Unsigned integer argument.

Unsigned hexadecimal integer in lowercase or uppercase.

To use buffers larger than 1024 bytes, use _snwprintf. For more information, see the documentation for the C run-time library.

Requirements

Minimum supported client

Windows 2000 Professional [desktop apps only]

Minimum supported server

Windows 2000 Server [desktop apps only]

Unicode and ANSI names

wsprintfW (Unicode) and wsprintfA (ANSI)

Функция vprintf, vfprintf, vsprintf, vsnprintf

Действия функций vprintf() , vfprintf() , vsprintf() и vsnprintf() эквивалентны действиям функций printf() , fprintf() , sprintf() и snprintf() соответственно, но список аргументов заменяется указателем на список аргументов. Этот указатель должен иметь тип va_list , который определен в заголовке .

В версии C99 к параметрам buf и format применен квалификатор restrict . Функция vsnprintf() добавлена в версии C99.

Пример

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

Что такое код wvsprinf

Writes formatted data to the specified buffer using a pointer to a list of arguments. The items pointed to by the argument list are converted and copied to an output buffer according to the corresponding format specification in the format-control string. The function appends a terminating null character to the characters it writes, but the return value does not include the terminating null character in its character count.

Syntax

Parameters

Type: LPTSTR

The buffer that is to receive the formatted output. The maximum size of the buffer is 1,024 bytes.

Type: LPCTSTR

The format-control specifications. In addition to ordinary ASCII characters, a format specification for each argument appears in this string. For more information about the format specification, see the wsprintf function.

Type: va_list

Each element of this list specifies an argument for the format-control string. The number, type, and interpretation of the arguments depend on the corresponding format-control specifications in the lpFmt parameter.

Return value

Type: int

If the function succeeds, the return value is the number of characters stored in the buffer, not counting the terminating null character.

If the function fails, the return value is less than the length of the expected output. To get extended error information, call GetLastError.

Security Considerations

Using this function incorrectly can compromise the security of your application. The string returned in lpOutput is not guaranteed to be NULL-terminated. Also, avoid the use of the %s format, which can lead to a buffer overrun. This can lead to a denial of service if it results in an access violation, or an attacker may inject executable code. Consider using one of the following alternatives: StringCbPrintf, StringCbPrintfEx, StringCbVPrintf, StringCbVPrintfEx, StringCchPrintf, StringCchPrintfEx, StringCchVPrintf, or StringCchVPrintfEx.

Remarks

The function copies the format-control string into the output buffer character by character, starting with the first character in the string. When it encounters a format specification in the string, the function retrieves the value of the next available argument (starting with the first argument in the list), converts that value into the specified format, and copies the result to the output buffer. The function continues to copy characters and expand format specifications in this way until it reaches the end of the format-control string. If there are more arguments than format specifications, the extra arguments are ignored. If there are not enough arguments for all of the format specifications, the results are undefined.

Requirements

Minimum supported client

Windows 2000 Professional [desktop apps only]

Minimum supported server

Windows 2000 Server [desktop apps only]

Unicode and ANSI names

wvsprintfW (Unicode) and wvsprintfA (ANSI)

Что такое код wvsprinf

vsprintf, _vsprintf_l, vswprintf, _vswprintf_l, __vswprintf_l

Write formatted output using a pointer to a list of arguments. More secure versions of these functions are available; see vsprintf_s, _vsprintf_s_l, vswprintf_s, _vswprintf_s_l.

buffer
Storage location for output.

count
Maximum number of characters to store, in the wide string versions of this function.

format
Format specification.

argptr
Pointer to list of arguments.

locale
The locale to use.

vsprintf and vswprintf return the number of characters written, not including the terminating null character, or a negative value if an output error occurs. If buffer or format is a null pointer, these functions invoke the invalid parameter handler, as described in Parameter Validation. If execution is allowed to continue, these functions return -1 and set errno to EINVAL.

For information on these and other error codes, see _doserrno, errno, _sys_errlist, and _sys_nerr.

Each of these functions takes a pointer to an argument list, and then formats and writes the given data to the memory pointed to by buffer.

The versions of these functions with the _l suffix are identical except that they use the locale parameter passed in instead of the current thread locale.

[!IMPORTANT] Using vsprintf, there is no way to limit the number of characters written, which means that code using this function is susceptible to buffer overruns. Use _vsnprintf instead, or call _vscprintf to determine how large a buffer is needed. Also, ensure that format is not a user-defined string. For more information, see Avoiding Buffer Overruns.

vswprintf conforms to the ISO C Standard, which requires the second parameter, count, of type size_t. To force the old nonstandard behavior, define _CRT_NON_CONFORMING_SWPRINTFS. The old behavior may not be in a future version, so code should be changed to use the new conformant behavior.

In C++, these functions have template overloads that invoke the newer, secure counterparts of these functions. For more information, see Secure Template Overloads.

Generic-Text Routine Mappings

Field Meaning
Winuser.h (include Windows.h)
Winuser.h (include Windows.h)
TCHAR.H routine _UNICODE & _MBCS not defined _MBCS defined _UNICODE defined
_vstprintf vsprintf vsprintf vswprintf
_vstprintf_l _vsprintf_l _vsprintf_l _vswprintf_l
Routine Required header Optional headers
vsprintf, _vsprintf_l and *
vswprintf, _vswprintf_l or , and *

* Required for UNIX V compatibility.

For additional compatibility information, see Compatibility.

Печальная судьба спецификаторов формата функции printf для символов Юникода в Visual C++

Поддержка Юникода в Windows появилась раньше, чем в большинстве остальных операционных систем. Из-за этого многие проблемы, связанные с представлением символов, в Windows решались не так, как в других системах, разработчики которых отложили внедрение нового стандарта до лучших времён [1]. Самый показательный пример: в Windows для представления символов Юникода используется кодировка UCS-2. Она была рекомендована Консорциумом Юникода, поскольку версия 1.0 поддерживала только 65 536 символов [2]. Пять лет спустя Консорциум передумал, но к тому времени менять что-то в Windows было уже поздно, так как на рынок уже были выпущены системы Win32s, Windows NT 3.1, Windows NT 3.5, Windows NT 3.51 и Windows 95 — все они использовали кодировку UCS-2 [3].

Но сегодня мы поговорим о строках форматирования функции printf.

Поскольку Юникод был принят в Windows раньше, чем в языке C, это означало, что разработчики Microsoft должны были придумать, как реализовать поддержку этого стандарта в среде выполнения C. В результате появились такие функции, как wcscmp, wcschr и wprintf. Что же касается строк форматирования в printf, то для них ввели следующие спецификаторы:

  • %s представляет строку той же ширины, что и строка форматирования;
  • %S представляет строку с шириной, обратной ширине строки форматирования;
  • %hs представляет обычную строку независимо от ширины строки форматирования;
  • %ws и %ls представляют широкую строку независимо от ширины строки форматирования.

Идея состояла в том, чтобы можно было написать такой код:

И при компиляции в режиме ANSI получить вот такой результат:

А при компиляции в режиме Юникод — такой [4]:

Поскольку спецификатор %s принимает строку той же ширины, что у строки форматирования, такой код будет работать корректно и в формате ANSI, и в формате Юникод. Также это решение очень упрощает преобразование уже написанного кода из формата ANSI в формат Юникод, так как на место спецификатора %s подставляется строка нужной ширины.

Когда поддержка Юникода была официально добавлена в C99, комитет по стандартизации языка C принял другую модель строк форматирования для функции printf:

  • %s и %hs представляют обычную строку;
  • %ls представляет широкую строку.

Тут-то и начались проблемы. За прошедшие к тому моменту шесть лет для Windows было написано огромное множество программ объёмом в миллиарды строк, и в них использовался старый формат. Как быть компиляторам Visual C и C++?

Было решено остаться на старой, нестандартной модели, чтобы не сломать все существующие в мире программы под Windows.

Если вы хотите, чтобы ваш код работал и в тех средах исполнения, которые придерживаются классических правил для printf, и в тех, которые следуют правилам стандарта C, вам придётся ограничиться спецификаторами %hs для обычных строк и %ls для широких. В этом случае гарантируется постоянство результатов, независимо от того, передаётся строка форматирования в функцию sprintf или wsprintf.

Вынесенное отдельно определение TSTRINGWIDTH позволяет писать, например, вот такой код:

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

Я выделил строки со спецификаторами, которые в C определены так же, как и в классическом формате, принятом в Windows [5]. Используйте эти спецификаторы, если хотите, чтобы ваш код выдавал одинаковые результаты в обоих форматах.

[1] Казалось бы, внедрение Юникода в Windows раньше прочих систем должно было дать Microsoft преимущество первого хода, но — по крайней мере в случае с Юникодом — оно обернулось для них «проклятием первопроходца», потому что остальные решили просто подождать до лучших времён, когда появятся более перспективные решения (такие как кодировка UTF-8), и только после этого внедрять Юникод в свои системы.

[2] Видимо, они полагали, что 65 536 символов должно было хватить на всех.

[3] Позже её заменили на UTF-16. К счастью, UTF-16 имеет обратную совместимость с UCS-2 для тех кодовых знаков, которые могут быть представлены в обеих кодировках.

[4] Формально версия для Юникода должна выглядеть так:

Дело в том, что wchar_t тогда ещё не был самостоятельным типом, и пока его не добавили в стандарт, он был всего лишь синонимом unsigned short. О перипетиях судьбы wchar_t можно почитать в отдельной статье.

[5] Классический формат, разработанный Windows, появился первым, так что это скорее стандарту C пришлось подстраиваться под него, а не наоборот.

Я благодарен автору за эту публикацию. Теперь стало понятно, как получилась вся эта путаница с «%s». Дело в то том, что наши пользователи постоянно задавали вопрос, почему PVS-Studio по-разному реагирует на их, как им кажется, «переносимый» код, в зависимости собирают они свой проект под Linux или Windows. Понадобилось сделать в описании диагностики V576 специальный отдельный раздел, посвященный этой теме (см. «Широкие строки»). После этой статьи всё становится ещё более понятно и очевидно. Думаю, эту заметку стоит прочитать всем, кто разрабатывает кроссплатформенные приложения. Читайте и расскажите коллегам.

Printf

printf

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

Наиболее ярким представителем этого семейства является функция 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-подобный синтаксис строки форматирования используют многие другие языки программирования

Помимо этого, благодаря наличию утилиты 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

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

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

  • 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 дополнять пробелами Используется для типов 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. Впрочем, эти типы могут присутствовать в реализациях на правах языковых расширений

:

  • аргументы типа 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

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

Например, рассмотрим реализацию Си, где тип char знаковый и имеет размер 8 бит, тип int имеет размер 32 бит, используется дополнительный способ кодирования отрицательных целых

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

Эти два вызова имеют один и тот же эффект и дают вывод 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 ). По-умолчанию записывается с правым выравниванием, знак пишется только для отрицательных чисел;
  • 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 (или wint 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). [15]

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

Второй стандарт языка Си (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

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

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

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

:

Пара знакового и беззнакового типов Имя макроса
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

Можно заметить, что для типов 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 представлением. Практически используется для записи переменных в файл.
Вывод

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

Уязвимости

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

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

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

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

:

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

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

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

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

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

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

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

:

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

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

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

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

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

:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

В вышеприведённом коде неявно предполагается, что пользователь не будет печатать 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 бита. [17]

Утилита printf

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

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

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

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

Ссылки

  1. Краткое описание языка BCPL
  2. Руководство по языку Би
  3. Описание функции sprintf в документации Perl
  4. Описание форматирующего оператора для строковых типов в Питоне
  5. Описание функции printf в составе PHP
  6. Описание функции java.io.PrintStream.printf() в Java 1.5
  7. Описание функции printf в документации Ruby
  8. Описание функции string.format в документации Lua
  9. Описание функции format в документации TCL
  10. Описание шаблона строки для 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, Formatting Strings
  14. Описание модуля Printf в документации OCaml
  15. § 7.11.1.1 ISO/IEC 9899:TC2, LC_NUMERIC определяет, в частности, форму представления разделителя дробной и целой части.
  16. Описание уязвимостей printf, Robert C. Seacord: Secure Coding in C and C++. Addison Wesley, September, 2005. ISBN 0-321-33572-4
  17. Описание проблем переноса приложений с 32 на 64 битную архитектуру

Источники

  • printf, fprintf, snprintf, vfprintf, vprintf, vsnprintf, vsprintf в стандарте ISO/IEC 9899:TC2 (ISO C) [3]
  • printf, fprintf, sprintf, snprintf в стандарте Single Unix [4]
  • vprintf, vfprintf, vsprintf, vsnprintf в стандарте POSIX[5]
  • wprintf, swprintf, wprintf в стандарте POSIX[6]
  • vfwprintf, vswprintf, vwprintf в стандарте POSIX[7]
  • wsprintf в MSDN[8]
  • wvnsprintf в MSDN [9]
  • wnsprintf в MSDN [10]
  • wvsprintf в MSDN [11]
  • wnsprintf в MSDN [12]
  • asprintf, vasprintf в man-pages в Linux [13], в документации к libc [14]
  • Описание синтаксиса строки форматирования в руководстве libc [15].
  • Описание строки форматирования в документации к Microsoft Visual Studio 2005 [16]
  • Описание register_printf_function[17], [18]

См. также

См. также в других словарях:

printf — printf обобщённое название семейства функций или методов стандартных или широкоизвестных коммерческих библиотек, или встроенных операторов некоторых языков программирования, используемых для форматного вывода вывода в различные потоки … Википедия

Printf — Saltar a navegación, búsqueda Un ejemplo de la función printf. Numerosos lenguajes de programación implementan una función printf, para mostrar una cadena con formato. Ésta, originaria del lenguaje de programación C, tiene un prototipo similar al … Wikipedia Español

Printf — est une commande Unix permettant de faire afficher une chaîne de caractères à l écran. C est aussi un nom de fonction du Langage C, du Perl et d autres langages informatiques permettant d afficher une ou plusieurs variables de façon formatée dans … Wikipédia en Français

Printf — The >Wikipedia

printf — Un exemple de la fonction printf. printf (pour l anglais print formatted, soit « imprimer formaté ») est une commande Unix permettant de faire afficher une chaîne de caractères à l écran. C est aussi un nom de fonction du langage C, et… … Wikipédia en Français

printf — Un ejemplo de la función printf. Numerosos lenguajes de programación implementan una función printf (print formated), para mostrar una cadena con formato. Ésta, originaria del lenguaje de programación C, tiene un prototipo similar al siguiente:… … Wikipedia Español

Printf() — … Википедия

printf — PRINT Formatted Standard Prozedur mit VARGS, http://www.desy.de/cgi bin/man cgiprintf … Acronyms

printf — ● /print F/ np. m. ►LANGC Fonction très >Dictionnaire d’informatique francophone

Проблемы с использованием кодов ваучеров PSN в PlayStation Store

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

Внимание! Ваучеры для пробной подписки PS Plus можно погасить только для учетных записей, которые не были раньше подписаны на PS Plus.

Пошаговая инструкция по погашению кодов ваучеров находится в статье «Как погасить код ваучера».

Мой ваучер поврежден

Если ваш код ваучера напечатан на бумажном чеке, обратитесь к продавцу для восстановления кода.

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

Мой код уже погашен

Проверьте историю транзакций каждой учетной записи, связанной с вашими системами PlayStation — добавление средств в бумажник будет обозначено как «Пополнение бумажника». Также вы можете проверить, есть ли уже материалы, полученные по ваучеру, в вашей библиотеке (или в списке загрузки на PS3 и PS Vita).

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

Мой ваучер для другого региона

На каждом ваучере указан регион, для которого предназначен код этого ваучера. К сожалению, коды ваучеров можно погасить только в PlayStation Store указанного региона — изменить регион учетной записи невозможно (регион выбирается при регистрации учетной записи).

Чтобы узнать регион вашей учетной записи, войдите в сеть на странице управления учетной записью > [Учетная запись] > [Данные учетной записи] и выберите раздел «Страна/регион».

Можно ли погасить код ваучера для детской учетной записи?

У детских учетных записей нет своего бумажника, поэтому нельзя непосредственно использовать ваучеры для пополнения бумажника. Если вы хотите использовать ваучер для пополнения бумажника для детской учетной записи, сначала попросите организатора семейного доступа погасить код для его учетной записи. Затем организатор семейного доступа сможет настроить месячный лимит расходов детской учетной записи с помощью средств родительского контроля (по умолчанию лимит равен 0 р.), чтобы предоставить детской учетной записи доступ к денежным средствам.

Если вы погашаете код ваучера PS Plus для детской учетной записи, помните о том, что возрастные ограничения закроют доступ к материалам, не подходящим по возрасту для владельца этой детской учетной записи*. В результате владельцы детских учетных записей не смогут получать преимущества PS Plus (такие как игры месяца) с возрастным рейтингом выше соответствующего возрасту владельца этой детской учетной записи.

*Некоторые пользователи предпочитают погашать коды ваучеров PlayStation Plus для связанной учетной записи организатора семейного доступа, который затем может поделиться всеми преимуществами подписки PS Plus со взрослыми членами семьи.

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

У вас другие проблемы с погашением кода ваучера?

  • Посетите страницу статуса служб PlayStation Network. Погашайте код ваучера только при «зеленом» статусе.
  • Если вы используете денежный ваучер, убедитесь, что сумма не превышает максимальный баланс бумажника 10500₽.
  • Если вы пытаетесь погасить код ваучера для получения материалов, убедитесь, что в вашей библиотеке еще нет этих материалов.
  • Выйдите из сети на странице управления учетной записью (в браузере) или выйдите из PlayStation Store и снова войдите в сеть, чтобы обновить данные учетной записи.
  • Убедитесь, что код ваучера все еще действителен. Срок действия кода указан на ваучере.
  • Для погашения некоторых кодов ваучеров требуется, чтобы к вашей учетной записи были добавлены данные кредитной или дебетовой карты. При попытке погасить код такого ваучера вы получите сообщение об этом. Инструкции находятся в статье «Как добавить карту».
  • Некоторые коды ваучеров требуется активировать при покупке. Проверьте свой ваучер — на обеих его сторонах может быть написано «Требуется активация карты перед оплатой». Если такой ваучер не работает, уточните у продавца, был ли он активирован.

Если ваша проблема не решена и не описана выше, свяжитесь с нами для получения помощи и предоставьте следующую информацию, по возможности в полном объеме.

Что такое программный код, применение, ошибки

Любая программа или онлайн-сервисы, например, Word, Microsoft Windows, WhatsApp или же браузер, которые ежедневно запускают сотни миллионов человек, так или иначе, состоят из особых инструкций. Или специального программного кода, который понятен машине, говорит, что ей делать или, наоборот, не делать. Или как правильно реагировать на действия пользователя. Что такое программный код, будет разобрано в этой статье.

Описание

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

Исходный код программы может состоять из нескольких файлов. При этом все они должны быть одинакового формата. Текст программы, содержащейся в них, должен быть написан на одном и том же языке. Правда, могут встречаться и исключения. Например, в веб-разработке в файле страницы могут содержаться несколько различных языков программирования и стандартов. В зависимости от сложности проекта, могут присутствовать такие языки и технологии, как PHP, HTML, JavaScript, Java и другие.

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

Качество кода

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

  • Читаемость кода. Одного взгляда на него должно хватать, чтобы обобщенно понять, что реализуется участком кода.
  • Присутствие понятных и ёмких комментариев. Данный параметр очень сильно влияет на читаемость, легкость в отладке, тестирование поддержки и устранение ошибок программного кода.
  • Низкая сложность.
  • Оптимизация кода. Организовать его стоит таким образом, чтобы программа использовала как можно меньше системных ресурсов, таких как память, время процессора и пространство жёсткого диска.
  • Отсутствие мусора. То есть не используемых переменных или блоков кода, в которой никогда не заходит управление программой.

Вредоносный программный код

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

Рекомендации по написанию хорошего кода

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

В частности, он предлагает всегда комментировать свой программный код. Что такое комментарий? Это понятное и краткое описание того, что происходит в данной строке кода или функции. Дело в том, что разработка определённой программы может затянуться на месяц или вообще приостановиться на некоторое время. Вернувшись к работе над проектом через пару месяцев, даже опытному программисту будет сложно разобраться в своей же программе. Но подробные комментарии смогут восстановить цепочку событий и поведение кода.

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

Имена переменных и выявление ошибок

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

Очень важно уделять большое внимание своевременному устранению ошибок. Что такое программный код, который исполняется идеально? Это код, в котором нет ошибок. То есть любое ветвление цикла или изменение переменной, или вовсе какие-либо непредвиденные действия пользователя, всегда приведут к ожидаемому результату. Это достигается за счёт тестирования готового программного продукта по несколько раз.

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

Оптимизация имеет колоссальное значение для написания работоспособной программы, которая будет экономно использовать ресурсы компьютера и при этом не допускать ошибок выполнения программного кода. Что такое оптимизированная программа? Это продукт, который способен выполнять весь заявленный функционал, ведя себя при этом «тихо» и экономно.

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

Заключение

Что такое программный код? Говоря простым языком, это набор инструкций и понятий для компьютера. Он содержит текст, который компилятор или интерпретатор могут превратить в понятный машине язык. То есть, по сути, программный код — это посредник между человеком и компьютером, который упрощает их взаимоотношения.

Код безопасности OTP tlsgn

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

Для онлайн шоппинга необходимы только карточка любого банка и подключение к Интернету.

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

Что означает ОТР tlsgn?

С такой системой безопасности сталкивался каждый, однако, далеко не все знают, что такое ОТP tlsgn. Чаще всего основной группой пользователей, которые используют такие пин-коды, являются удаленные трейдеры, майнеры или люди, которые часто совершают покупки в Интернете.

Название технологии OTP расшифровывается, как one time password, что в переводе обозначает «одноразовый пароль».

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

Как правило, пароли генерируются торговой площадкой или операционной системой iOS и Android. Главное преимущество такой формы двухфакторной авторизации – полная защита от мошенничества.

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

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

Генерация паролей полностью рандомна – состоит из случайных чисел. Никакой определенной схемы прогнозирования последующих кодов нет.

Это также необходимо для защиты от хакерских атак. Однако, существуют разные алгоритмы реализации технологии ОТР, которые имеют похожую структуру, но имеют отличия в деталях:

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

Самый популярный способ распространения ОТР паролей – посредством СМС-сообщений.

Что делать, если приходит код безопасности ОТР tlsgn?

Всего существует 4 основных способа, при помощи которых ОТР пароли доставляются пользователю:

  • через специальное оборудование – электронные токены, которые клиент носит с собой, и которые выводят одноразовые идентификаторы на экран устройства;
  • через одну или несколько программ, которые запускаются на телефоне или планшете;
  • через узлы связи сервер – другие устройства (самый популярный пример СМС);
  • через скретч-карты или листы, на которых заранее напечатаны все пароли, пригодные для дальнейшего использования.

Если на телефон приходят оповещения о получении ОТР-паролей, существуют два варианта:

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

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

Что такое одноразовый PIN-код и когда он нужен?

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

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

Одноразовые коды безопасности – продвинутый способ защиты от мошенничества, которые повсеместно используются банками и торговыми площадками. Они минимизируют риски и позволяют проводить финансовые операции в Интернете.

Новое телефонное мошенничество с кодами подтверждения

«Звонок с незнакомого номера. Беру трубку. Мужской голос:
— Здравствуйте, прошу прощения. У меня номер на модеме очень похож на ваш. Я отправил код активации сообщением, но ошибся в одной цифре. Посмотрите, пожалуйста, вам приходило СМС?

Мужчина называет мой номер и номер своего модема. Лезу смотреть СМС-сообщения, действительно, код активации пришел мне.

Нет ничего проще, чем сделать доброе дело и продиктовать незнакомцу цифры кода активации его модема. Но меня что-то настораживает:
— Да, мне пришло СМС с кодом, но давайте вы отправите мне СМС с номера, который похож на мой, чтобы я убедился, что действительно ваш номер похож на мой. И я пока не знаю, от чего это код активации, вдруг это доступ к моему счету.

На той стороне что-то идет не так. Тревога, нотки в голосе меняются.
— Понимаете, это модем, я не могу отправить с него СМС.

Подсказываю решение по отправке СМС:
— Переставьте сим-карту в телефон, это несложно.

На той стороне мычат и вешают трубку.

Теперь смотрим сообщение подробно:

Ищу информацию о том, что такое «Легкий платеж». Она в два клика обнаруживается на сайте МТС:

Замечательно. Если я бы я сообщил код активации, с моего счета можно было бы оплачивать мобильный телефон, интернет, выводить средства на электронные деньги и так далее.

Разумеется, мошенники никакого СМС с несуществующего модема не прислали. Развод не состоялся. Зато по запросу «Легкий платеж МТС мошенничество» в Яндексе выдается куча статей.

Кстати, примечательно и на скриншоте выше видно, что МТС системные сообщения шлет, подписываясь МТС, а код активации запрашивает с непримечательного +79150008962. Это может играть мошенникам на руку.

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

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

Илон Маск рекомендует:  Что такое код asp logextfileuriquery
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL