printf is a C standard library function that formats text and writes it to standard output.

The name, printf is short for print formatted where print refers to output to a printer although the functions are not limited to printer output.

The standard library provides many other similar functions that form a family of printf-like functions. These functions accept a format string parameter and a variable number of value parameters that the function serializes per the format string and writes to an output stream or a string buffer.

The format string is encoded as a template language consisting of verbatim text and format specifiers that each specify how to serialize a value. As the format string is processed left-to-right, a subsequent value is used for each format specifier found. A format specifier starts with a % character and has one or more following characters that specify how to serialize a value.

The format string syntax and semantics is the same for all of the functions in the printf-like family.

Mismatch between the format specifiers and count and type of values can cause a crash or vulnerability.

The printf format string is complementary to the scanf format string, which provides formatted input (lexing a.k.a. parsing). Both format strings provide relatively simple functionality compared to other template engines, lexers and parsers.

The formatting design has been copied in other programming languages.

History

1950s: Fortran

Early programming languages like Fortran used special statements with different syntax from other calculations to build formatting descriptions. In this example, the format is specified on line 601, and the PRINT command refers to it by line number:

Hereby:

  • 4H indicates a string of 4 characters " A= " (H means Hollerith Field);
  • I5 indicates an integer field of width 5;
  • F10.2 indicates a floating-point field of width 10 with 2 digits after the decimal point.

An output with input arguments 100, 200, and 1500.25 might look like this:

1960s: BCPL and ALGOL 68

In 1967, BCPL appeared. Its library included the writef routine. An example application looks like this:

Hereby:

  • %I2 indicates an integer of width 2 (the order of the format specification's field width and type is reversed compared to C's printf);
  • %I5 indicates an integer of width 5;
  • *N is a BCPL language escape sequence representing a newline character (for which C uses the escape sequence \n).

In 1968, ALGOL 68 had a more function-like API, but still used special syntax (the $ delimiters surround special formatting syntax):

In contrast to Fortran, using normal function calls and data types simplifies the language and compiler, and allows the implementation of the input/output to be written in the same language.

These advantages were thought to outweigh the disadvantages (such as a complete lack of type safety in many instances) up until the 2000s, and in most newer languages of that era I/O is not part of the syntax.

People have since learned that this potentially results in consequences, ranging from security exploits to hardware failures (e.g., phone's networking capabilities being permanently disabled after trying to connect to an access point named "%p%s%s%s%s%n"). Modern languages, such as C 20 and later, tend to include format specifications as a part of the language syntax, which restore type safety in formatting to an extent, and allow the compiler to detect some invalid combinations of format specifiers and data types at compile time.

1970s: C

In 1973, printf was included as a C standard library routine as part of Version 4 Unix.

1990s: Shell command

In 1990, a printf shell command was attested as part of 4.3BSD-Reno. It is modeled after the C standard library function.

In 1991, a printf command was included with GNU shellutils (now part of GNU Core Utilities).

2000s: -Wformat safety

The need to do something about the range of problems resulting from lack of type safety has prompted attempts to make the C compiler printf-aware.

The -Wformat option of GCC allows compile-time checks to printf calls, enabling the compiler to detect a subset of invalid calls (and issue either a warning or an error, stopping the compilation altogether, depending on other flags).

Since the compiler is inspecting printf format specifiers, enabling this effectively extends the C syntax by making formatting a part of it.

2020s: C 20 Format Specifiers and C 23 print

As said above, numerous issues with printf()'s lack of type safety resulted in the revision of approach to formatting, and C 20 onwards include format specifications in the language to enable type-safe formatting.

The approach (and syntax) of C 20 std::format resulted from effectively incorporating Victor Zverovich's libfmt API into the language specification (Zverovich wrote the first draft of the new format proposal); consequently, libfmt is an implementation of the C 20 format specification.

The formatting function has been combined with output in C 23, which provides the std::print command as a replacement for printf().

As the format specification has become a part of the language syntax, a C compiler is able to prevent invalid combinations of types and format specifiers in many cases. Unlike the -Wformat option, this is not an optional feature.

The format specification of libfmt and std::format is, in itself, an extensible "mini-language" (referred to as such in the specification), an example of a domain-specific language.

Incorporation of a separate, domain specific mini-language specifically for formatting into the C language syntax for std::print, therefore, completes the historical cycle, bringing the state-of-the-art (as of 2024) back to what it was in the case of FORTRAN's first PRINT implementation in the 1950s discussed in the beginning of this section.

Format specifier

Formatting of a value is specified as markup in the format string. For example, the following outputs Your age is and then the value of the variable age in decimal format.

Syntax

The syntax for a format specifier is:

%[parameter][flags][width][.precision][length]type

Parameter field

The parameter field is optional. If included, then matching specifiers to values is not sequential. The numeric value n selects the n-th value parameter.

This is a POSIX extension; not C99.

This field allows for using the same value multiple times in a format string instead of having to pass the value multiple times. If a specifier includes this field, then subsequent specifiers must also.

For example,

outputs: 17 0x11; 16 0x10.

This field is particularly useful for localizing messages to different natural languages that use different word orders.

In Microsoft Windows, support for this feature is via a different function, printf_p.

Flags field

The flags field can be zero or more of (in any order):

Width field

The width field specifies the minimum number of characters to output. If the value can be represented in fewer characters, then the value is left-padded with spaces so that output is the number of characters specified. If the value requires more characters, then the output is longer than the specified width. A value is never truncated.

For example, printf("=", 12); specifies a width of 3 and outputs 12 with a space on the left to output 3 characters. The call printf("=", 1234); outputs 1234 which is 4 characters long since that is the minimum width for that value even though the width specified is 3.

If the width field is omitted, the output is the minimum number of characters for the value.

If the field is specified as *, then the width value is read from the list of values in the call. For example, printf("%*d", 3, 10); outputs 10 where the second parameter, 3, is the width (matches with *) and 10 is the value to serialize (matches with d).

Though not part of the width field, a leading zero is interpreted as the zero-padding flag mentioned above, and a negative value is treated as the positive value in conjunction with the left-alignment - flag also mentioned above.

The width field can be used to format values as a table (tabulated output). But, columns do not align if any value is larger than fits in the width specified. For example, notice that the last line value (1234) does not fit in the first column of width 3 and therefore the column is not aligned.

Precision field

The precision field usually specifies a maximum limit of the output, depending on the particular formatting type. For floating-point numeric types, it specifies the number of digits to the right of the decimal point to which the output should be rounded; for %g and %G it specifies the total number of significant digits (before and after the decimal, not including leading or trailing zeroes) to round to. For the string type, it limits the number of characters that should be output, after which the string is truncated.

The precision field may be omitted, or a numeric integer value, or a dynamic value when passed as another argument when indicated by an asterisk (*). For example, printf("%.*s", 3, "abcdef"); outputs abc.

Length field

The length field can be omitted or be any of:

Platform-specific length options came to exist prior to widespread use of the ISO C99 extensions, including:

ISO C99 includes the inttypes.h header file that includes a number of macros for platform-independent printf coding. For example: printf("%" PRId64, t); specifies decimal format for a 64-bit signed integer. Since the macros evaluate to a string literal, and the compiler concatenates adjacent string literals, the expression "%" PRId64 compiles to a single string.

Macros include:

Type field

The type field can be any of:

Custom data type formatting

A common way to handle formatting with a custom data type is to format the custom data type value into a string, then use the %s specifier to include the serialized value in a larger message.

Some printf-like functions allow extensions to the escape-character-based mini-language, thus allowing the programmer to use a specific formatting function for non-builtin types. One is the (now deprecated) glibc's register_printf_function(). However, it is rarely used due to the fact that it conflicts with static format string checking. Another is Vstr custom formatters, which allows adding multi-character format names.

Some applications (like the Apache HTTP Server) include their own printf-like function, and embed extensions into it. However these all tend to have the same problems that register_printf_function() has.

The Linux kernel printk function supports a number of ways to display kernel structures using the generic %p specification, by appending additional format characters. For example, %pI4 prints an IPv4 address in dotted-decimal form. This allows static format string checking (of the %p portion) at the expense of full compatibility with normal printf.

Family

Variants of printf:

fprintf outputs to a system file object instead of standard output.

sprintf writes to a string buffer instead of standard output.

snprintf provides a level of safety over sprintf since the caller provides a length n that is the length of the output buffer in bytes (including space for the trailing nul).

asprintf's first argument is a handle) (char **) which is then set to point to an allocated string of sufficient size to contain the output.

Each of these has a variant that accepts va_list rather than comma-separated parameters: vfprintf, vsprintf, vsnprintf, vasprintf.

These functions return the number bytes that would be printed (snprintf may return a value >= n when output is truncated). Errors return -1.

Vulnerabilities

Format string attack

Extra value parameters are ignored, but if the format string has more format specifiers than value parameters passed the behavior is undefined. For some C compilers, an extra format specifier results in consuming a value even though there isn't one. This can allow the format string attack. Generally, for C, arguments are passed on the stack. If too few arguments are passed, then printf can read past the end of the stack frame, thus allowing an attacker to read the stack.

Some compilers, like the GNU Compiler Collection, will statically check the format strings of printf-like functions and warn about problems (when using the flags -Wall or -Wformat). GCC will also warn about user-defined printf-style functions if the non-standard "format" __attribute__ is applied to the function.

Uncontrolled format string exploit

The format string is often a string literal, which allows static analysis of the function call. However, the format string can be the value of a variable, which allows for dynamic formatting but also a security vulnerability known as an uncontrolled format string exploit.

Memory write

Although an output function on the surface, printf allows writing to a memory location specified by an argument via %n. This functionality is occasionally used as a part of more elaborate format-string attacks.

The %n functionality also makes printf accidentally Turing-complete even with a well-formed set of arguments. A game of tic-tac-toe written in the format string is a winner of the 27th IOCCC.

Programming languages with printf

Notable programming languages that include printf or printf-like functionality:

Excluded are languages that use format strings that deviate from the style in this article (such as AMPL and Elixir), languages that inherit their implementation from the JVM or other environment (such as Clojure and Scala), and languages that do not have a standard native printf implementation but have external libraries which emulate printf behavior (such as JavaScript).

See also

  • "Hello, World!" program – A basic example program first featured in The C Programming Language (the "K&R Book"), which in the C example uses printf to output the message "Hello, World!"
  • Format (Common Lisp) – function in Common Lisp that can produce formatted text using a format string similar to the printf format stringPages displaying wikidata descriptions as a fallback
  • C standard library – Standard library for the C programming language
  • Format string attack – Type of software vulnerabilityPages displaying short descriptions of redirect targets
  • std::iostream – C standard library header for input/outputPages displaying short descriptions of redirect targets
  • ML (programming language) – General purpose functional programming language
  • printf debugging – Fixing defects in an engineered systemPages displaying short descriptions of redirect targets
  • printf (Unix) – Standard UNIX utility
  • printk – Linux kernel C function
  • scanf – Control parameter used in programming languages
  • string interpolation – Replacing placeholders in a string with values

Notes

References

External links

  • C reference for std::fprintf
  • gcc printf format specifications quick reference
  • printf: print formatted output – System Interfaces Reference, The Single UNIX Specification, Version 4 from The Open Group
  • The Formatter specification in Java 1.5
  • GNU Bash printf(1) builtin

printf

GitHub sho011/printf this is a team project

Perl I/O Learning Objectives ppt download

GitHub dr8co/printf A custom implementation of printf() in C.

C Programming Basics The printf() function YouTube