
"C++" spelled as-is can result in unexpected rendering, such as C++20 was released before C++17 renders as C20 was released before C17 Make consistent use of `[source,cpp]`.
70 lines
2.3 KiB
Plaintext
70 lines
2.3 KiB
Plaintext
== Why is this an issue?
|
|
|
|
In contrast to C printf-like functions, the `std::format` family of formatting functions provides
|
|
a safer and more robust interface for performing text formatting.
|
|
|
|
Firstly, {cpp} formatting facilities perform validation of the format string against the type
|
|
of the formatted argument. If the validation fails, it is reported as a compilation error
|
|
for the calls of `std::format` and via exception for `std::vformat`.
|
|
|
|
Secondly, the relation between the type and format specifier is more abstract.
|
|
In particular, `{:d}` can be used to format any integer type, regardless of its size and signedness.
|
|
Similarly, `{:f}` works for any floating point type.
|
|
Furthermore, `{}` can be used for any type with default format spec, which makes it usable in the generic context.
|
|
|
|
Finally, the `std::format` API can be extended to support custom types with the dedicated format specification via
|
|
`std::formatter` specializations.
|
|
|
|
This rule raises issues for calls of the `sprintf` and `snprintf` functions that can be replaced by the {cpp} formatting functions.
|
|
|
|
=== Noncompliant code example
|
|
|
|
[source,cpp]
|
|
----
|
|
void printFunc(char* out, size_t n) {
|
|
sprintf(out, "%u %s", 10u, “text”); // Noncompliant
|
|
std::snprintf(out, n, "%i %% %LG", 10, 10.0L); // Noncompliant
|
|
}
|
|
----
|
|
|
|
=== Compliant solution
|
|
|
|
[source,cpp]
|
|
----
|
|
void printFunc(char* out) {
|
|
std::format_to(out, “{:d} {:s}”, 10u, text); // Compliant
|
|
// or
|
|
std::format_to(out, “{} {}”, 10u, text); // Compliant
|
|
|
|
std::format_to_n(out, ”{:d} % {:G}”, 10, 10.0L); // Compliant
|
|
// or
|
|
std::format_to_n(out, ”{} % {:G}”, 10, 10.0L); // Compliant
|
|
}
|
|
----
|
|
|
|
Other printf-like functions are not concerned by this rule:
|
|
|
|
[source,cpp]
|
|
----
|
|
void printFunc(FILE* f) {
|
|
printf("%i", 10); // Compliant, no direct remplacment
|
|
std::fprintf(f, "%f", 10.0); // Compliant, no direct remplacment
|
|
}
|
|
----
|
|
|
|
=== Exceptions
|
|
|
|
The rule does not raise an issue if the format string passed to a printf-like function is computed dynamically
|
|
instead of being spelled in the source code:
|
|
|
|
[source,cpp]
|
|
----
|
|
char const* localizedFormatString(unsigned id);
|
|
/* …. */
|
|
snprintf(buffer, localizedFormatString(123), 10, 20)
|
|
----
|
|
|
|
While `std::vformat` may be used in such cases, it would require a change of the format string,
|
|
which may not be actionable.
|
|
|