1.. _module-pw_string: 2 3--------- 4pw_string 5--------- 6String manipulation is a very common operation, but the standard C and C++ 7string libraries have drawbacks. The C++ functions are easy-to-use and powerful, 8but require too much flash and memory for many embedded projects. The C string 9functions are lighter weight, but can be difficult to use correctly. Mishandling 10of null terminators or buffer sizes can result in serious bugs. 11 12The ``pw_string`` module provides the flexibility, ease-of-use, and safety of 13C++-style string manipulation, but with no dynamic memory allocation and a much 14smaller binary size impact. Using ``pw_string`` in place of the standard C 15functions eliminates issues related to buffer overflow or missing null 16terminators. 17 18Compatibility 19============= 20C++17 21 22pw::string::Format 23================== 24The ``pw::string::Format`` and ``pw::string::FormatVaList`` functions provide 25safer alternatives to ``std::snprintf`` and ``std::vsnprintf``. The snprintf 26return value is awkward to interpret, and misinterpreting it can lead to serious 27bugs. 28 29Size report: replacing snprintf with pw::string::Format 30------------------------------------------------------- 31The ``Format`` functions have a small, fixed code size cost. However, relative 32to equivalent ``std::snprintf`` calls, there is no incremental code size cost to 33using ``Format``. 34 35.. include:: format_size_report 36 37pw::StringBuilder 38================= 39``pw::StringBuilder`` facilitates building formatted strings in a fixed-size 40buffer. It is designed to give the flexibility of ``std::string`` and 41``std::ostringstream``, but with a small footprint. 42 43Supporting custom types with StringBuilder 44------------------------------------------ 45As with ``std::ostream``, StringBuilder supports printing custom types by 46overriding the ``<<`` operator. This is is done by defining ``operator<<`` in 47the same namespace as the custom type. For example: 48 49.. code-block:: cpp 50 51 namespace my_project { 52 53 struct MyType { 54 int foo; 55 const char* bar; 56 }; 57 58 pw::StringBuilder& operator<<(pw::StringBuilder& sb, const MyType& value) { 59 return sb << "MyType(" << value.foo << ", " << value.bar << ')'; 60 } 61 62 } // namespace my_project 63 64Internally, ``StringBuilder`` uses the ``ToString`` function to print. The 65``ToString`` template function can be specialized to support custom types with 66``StringBuilder``, though it is recommended to overload ``operator<<`` instead. 67This example shows how to specialize ``pw::ToString``: 68 69.. code-block:: cpp 70 71 #include "pw_string/to_string.h" 72 73 namespace pw { 74 75 template <> 76 StatusWithSize ToString<MyStatus>(MyStatus value, std::span<char> buffer) { 77 return CopyString(MyStatusString(value), buffer); 78 } 79 80 } // namespace pw 81 82Size report: replacing snprintf with pw::StringBuilder 83------------------------------------------------------ 84StringBuilder is safe, flexible, and results in much smaller code size than 85using ``std::ostringstream``. However, applications sensitive to code size 86should use StringBuilder with care. 87 88The fixed code size cost of StringBuilder is significant, though smaller than 89``std::snprintf``. Using StringBuilder's << and append methods exclusively in 90place of ``snprintf`` reduces code size, but ``snprintf`` may be difficult to 91avoid. 92 93The incremental code size cost of StringBuilder is comparable to ``snprintf`` if 94errors are handled. Each argument to StringBuilder's ``<<`` expands to a 95function call, but one or two StringBuilder appends may have a smaller code size 96impact than a single ``snprintf`` call. 97 98.. include:: string_builder_size_report 99 100Future work 101=========== 102* StringBuilder's fixed size cost can be dramatically reduced by limiting 103 support for 64-bit integers. 104* Consider integrating with the tokenizer module. 105