pw_string#
Efficient, easy, and safe string manipulation
Efficient: No memory allocation, no pointer indirection.
Easy: Use the string API you already know.
Safe: Never worry about buffer overruns or undefined behavior.
Pick three! If you know how to use std::string
, just use
pw::InlineString
in the same way:
// Create a string from a C-style char array; storage is pre-allocated!
pw::InlineString<16> my_string = "Literally";
// We have some space left, so let's add to the string.
my_string.append('?', 3); // "Literally???"
// Let's try something evil and extend this past its capacity 😈
my_string.append('!', 8);
// Foiled by a crash! No mysterious bugs or undefined behavior.
Need to build up a string? pw::StringBuilder
works like
std::ostringstream
, but with most of the efficiency and memory benefits
of pw::InlineString
:
// Create a pw::StringBuilder with a built-in buffer
pw::StringBuffer<32> my_string_builder = "Is it really this easy?";
// Add to it with idiomatic C++
my_string << " YES!";
// Use it like any other string
PW_LOG_DEBUG("%s", my_string_builder.c_str());
Check out pw_string: Guide for more code samples.
Stable C++14 C++17 Code Size Impact: 500 to 1500 bytes
Background#
String manipulation on embedded systems can be surprisingly challenging. C strings are light weight but come with many pitfalls for those who don’t know the standard library deeply. C++ provides string classes that are safe and easy to use, but they consume way too much code space and are designed to be used with dynamic memory allocation.
Embedded systems need string functionality that is both safe and suitable for resource-constrained platforms.
Our solution#
pw_string
provides safe string handling functionality with an API that
closely matches that of std::string
, but without dynamic memory allocation
and with a much smaller binary size impact.
Who this is for#
pw_string
is useful any time you need to handle strings in embedded C++.
Is it right for you?#
If your project written in C, pw_string
is not a good fit since we don’t
currently expose a C API.
For larger platforms where code space isn’t in short supply and dynamic memory
allocation isn’t a problem, you may find that std::string
meets your needs.
Tip
pw_string
works just as well on larger embedded platforms and host
systems. Using pw_string
even when you might get away with std:string
gives you the flexibility to move to smaller platforms later with much less
rework.
Here are some size reports that may affect whether pw_string
is right for
you.
Size comparison: snprintf versus pw::StringBuilder#
pw::StringBuilder
is safe, flexible, and results in much smaller
code size than using std::ostringstream
. However, applications sensitive to
code size should use pw::StringBuilder
with care.
The fixed code size cost of pw::StringBuilder
is significant, though
smaller than std::snprintf
. Using pw::StringBuilder
’s <<
and
append
methods exclusively in place of snprintf
reduces code size, but
snprintf
may be difficult to avoid.
The incremental code size cost of pw::StringBuilder
is comparable to
snprintf
if errors are handled. Each argument to
pw::StringBuilder
’s <<
method expands to a function call, but
one or two pw::StringBuilder
appends may have a smaller code size
impact than a single snprintf
call.
Label |
Segment |
Delta |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Total StringBuilder cost when used alongside snprintf |
FLASH
|
+1,584 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
StringBuilder cost when completely replacing snprintf |
FLASH
|
+664 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Incremental cost relative to snprintf for 10 strings |
FLASH
|
-32 |
Size comparison: snprintf versus pw::string::Format#
The pw::string::Format
functions have a small, fixed code size
cost. However, relative to equivalent std::snprintf
calls, there is no
incremental code size cost to using pw::string::Format
.
Label |
Segment |
Delta |
||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Format instead of snprintf once, return size |
FLASH
|
+96 |
||||||||||||||||||||||||
Format instead of snprintf 10 times, handle errors |
FLASH
|
+32 |
||||||||||||||||||||||||
Format instead of snprintf 50 times, no error handling |
FLASH
|
+112 |
Roadmap#
StringBuilder’s fixed size cost can be dramatically reduced by limiting support for 64-bit integers.
Consider integrating with the tokenizer module.
Compatibility#
C++17, C++14 (pw::InlineString
)
Getting started#
GN#
Add $dir_pw_string
to the deps
list in your pw_executable()
build
target:
pw_executable("...") {
# ...
deps = [
# ...
"$dir_pw_string",
# ...
]
}
See //source/BUILD.gn in the Pigweed Sample Project for an example.
Zephyr#
Add CONFIG_PIGWEED_STRING=y
to the Zephyr project’s configuration.
Roadmap#
The fixed size cost of
pw::StringBuilder
can be dramatically reduced by limiting support for 64-bit integers.pw_string
may be integrated with pw_tokenizer.