modernize-use-std-print¶
Converts calls to printf, fprintf, absl::PrintF and
absl::FPrintf to equivalent calls to C++23’s std::print or
std::println as appropriate, modifying the format string appropriately.
The replaced and replacement functions can be customised by configuration
options. Each argument that is the result of a call to
std::string::c_str() and std::string::data() will have that
now-unnecessary call removed in a similar manner to the
readability-redundant-string-cstr check.
In other words, it turns lines like:
fprintf(stderr, "The %s is %3d\n", description.c_str(), value);
into:
std::println(stderr, "The {} is {:3}", description, value);
If the ReplacementPrintFunction or ReplacementPrintlnFunction options
are left at or set to their default values then this check is only enabled
with -std=c++23 or later.
Macros starting with PRI and __PRI from <inttypes.h> are
expanded, escaping is handled and adjacent strings are concatenated to form
a single StringLiteral before the format string is converted. Use of
any other macros in the format string will cause a warning message to be
emitted and no conversion will be performed. The converted format string
will always be a single string literal.
The check doesn’t do a bad job, but it’s not perfect. In particular:
It assumes that the format string is correct for the arguments. If you get any warnings when compiling with
-Wformatthen misbehaviour is possible.At the point that the check runs, the AST contains a single
StringLiteralfor the format string where escapes have been expanded. The check tries to reconstruct escape sequences, they may not be the same as they were written (e.g."\x41\x0a"will become"A\n"and"ab" "cd"will become"abcd".)It supports field widths, precision, positional arguments, leading zeros, leading
+, alignment and alternative forms.Use of any unsupported flags or specifiers will cause the entire statement to be left alone and a warning to be emitted. Particular unsupported features are:
The
%'flag for thousands separators.The glibc extension
%m.
printfand similar functions return the number of characters printed.std::printdoes not. This means that any invocations that use the return value will not be converted. Unfortunately this currently includes explicitly-casting tovoid. Deficiencies in this check mean that any invocations insideGCCcompound statements cannot be converted even if the resulting value is not used.
If conversion would be incomplete or unsafe then the entire invocation will be left unchanged.
If the call is deemed suitable for conversion then:
printf,fprintf,absl::PrintF,absl::FPrintFand any functions specified by thePrintfLikeFunctionsoption orFprintfLikeFunctionsare replaced with the function specified by theReplacementPrintlnFunctionoption if the format string ends with\norReplacementPrintFunctionotherwise.the format string is rewritten to use the
std::formatterlanguage. If a\nis found at the end of the format string not preceded byrthen it is removed andReplacementPrintlnFunctionis used rather thanReplacementPrintFunction.any arguments that corresponded to
%pspecifiers thatstd::formatterwouldn’t accept are wrapped in astatic_casttoconst void *.any arguments that corresponded to
%sspecifiers where the argument is ofsigned charorunsigned chartype are wrapped in areinterpret_cast<const char *>.any arguments where the format string and the parameter differ in signedness will be wrapped in an appropriate
static_castifStrictModeis enabled.any arguments that end in a call to
std::string::c_str()orstd::string::data()will have that call removed.
Options¶
- StrictMode¶
When
true, the check will add casts when converting from variadic functions likeprintfand printing signed or unsigned integer types (including fixed-width integer types from<cstdint>,ptrdiff_t,size_tandssize_t) as the opposite signedness to ensure that the output matches that ofprintf. This does not apply when converting from non-variadic functions such asabsl::PrintFandfmt::printf. For example, withStrictModeenabled:int i = -42; unsigned int u = 0xffffffff; printf("%u %d\n", i, u);
would be converted to:
std::print("{} {}\n", static_cast<unsigned int>(i), static_cast<int>(u));
to ensure that the output will continue to be the unsigned representation of
-42and the signed representation of0xffffffff(often4294967254and-1respectively.) Whenfalse, these casts will not be added which may cause a change in the output. Default isfalse.
- PrintfLikeFunctions¶
A semicolon-separated list of regular expressions matching the (fully qualified) names of functions to replace, with the requirement that the first parameter contains the printf-style format string and the arguments to be formatted follow immediately afterwards. Qualified member function names are supported, but the replacement function name must be unqualified. If neither this option nor
FprintfLikeFunctionsare set then the default value isprintf; absl::PrintF, otherwise it is the empty string.
- FprintfLikeFunctions¶
A semicolon-separated list of regular expressions matching the (fully qualified) names of functions to replace, with the requirement that the first parameter is retained, the second parameter contains the printf-style format string and the arguments to be formatted follow immediately afterwards. Qualified member function names are supported, but the replacement function name must be unqualified. If neither this option nor
PrintfLikeFunctionsare set then the default value isfprintf;absl::FPrintF, otherwise it is the empty string.
- ReplacementPrintFunction¶
The function that will be used to replace
printf,fprintfetc. during conversion rather than the defaultstd::printwhen the original format string does not end with\n. It is expected that the function provides an interface that is compatible withstd::print. A suitable candidate would befmt::print.
- ReplacementPrintlnFunction¶
The function that will be used to replace
printf,fprintfetc. during conversion rather than the defaultstd::printlnwhen the original format string ends with\n. It is expected that the function provides an interface that is compatible withstd::println. A suitable candidate would befmt::println.
- PrintHeader¶
The header that must be included for the declaration of
ReplacementPrintFunctionso that a#includedirective can be added if required. IfReplacementPrintFunctionisstd::printthen this option will default to<print>, otherwise this option will default to nothing and no#includedirective will be added.