rspec/rules/S6494/cfamily/rule.adoc
Marco Borgeaud 072e67b8d4
Fix asciidoc w.r.t. C++ (#3519)
"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]`.
2023-12-21 15:51:41 +01:00

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.