Flash Strings¶
Introduction¶
Strings are basically just arrays of char, but have additional methods to allow them to be used more easily.
These methods are consistent with Wiring String
, so should be reasonably familiar.
length()
returns the number of characters in the String, excluding the NUL terminatorsize()
returns the number of bytes of storage used
For example, “123” is actually stored as { '1', '2', '3', '\0' }
so the length is 3 and the size is 4.
However, “1234” is stored as { '1', '2', '3', '4', '\0' }
so the length is 4 and the size is 8.
Using Strings¶
Note
You can use FSTR::String
or the Sming-provided FlashString
alias to work with Strings.
Within a function:
DEFINE_FSTR_LOCAL(myFlashString, "This is my flash string");
Serial.println(myFlashString);
Serial.printf("myFlashString has %u chars and occupies %u bytes\n", myFlashString.length(), myFlashString.size());
To use Strings across translation units, we do this in the header:
DECLARE_FSTR(myFlashString);
And in a source file:
DEFINE_FSTR(myFlashString, "I am a flash string\0I've got a Naughty NUL.");
You can generally use a Flash String anywhere you can use a regular Wiring String as it has
an implicit ::String() operator. Note that WString
is used within the library for disambiguation.
Inline Strings¶
Use the FS()
macro to create Flash Strings inline:
Serial.println(FS("A Flash String"));
Note
The macro makes use of FS_PTR()
which creates the structure and returns a pointer to it.
It behaves like a function call, although the compiler inlines the code.
Therefore FS() may only be used within functions. At file scope you’ll get this error:
statement-expressions are not allowed outside functions nor in template-argument lists
The example above doesn’t provide any improvement over F
as there are no
Flash String overloads available, so is equivalent to this:
String s = FS("A Flash String");
Serial.println(s);
However, it’s rather different if you pass it to a function which recognises Flash Strings, like this:
FSTR::println(Serial, FS("A Flash String"));
This is equivalent to:
FS("A Flash String").printTo(Serial);
Serial.println();
FSTR::String::printTo()
uses no heap and imposes no restriction on the string length.
Nested Inline Strings¶
It would be really useful to be able to use inline Strings this within nested structures, and this can be done provided those structures are in RAM.
Important
Inline Strings cannot be used when defining Vectors or Maps.
Here’s is a simplified structure we will attempt to initialize:
static const struct {
FlashString* string;
} flashData PROGMEM = { FS_PTR("Inline Flash String") };
Serial.println(*flashData.string);
The static flashData structure gets initialised at runtime on first use, as per C++ rules.
This attempts to copy our pointer into the flashData structure which clearly it cannot do
as it’s in PROGMEM
, so we get a LOAD/STORE error. We must remove PROGMEM.
Avoiding the heap¶
Instead of using a temporary Wiring String, you can use LOAD_FSTR()
to load the
content into a temporary stack buffer:
DEFINE_FSTR(globalTest, "This is a testing string");
void func()
{
LOAD_FSTR(local, globalTest);
printf("%s, %u characters, buffer is %u bytes\n", local, globalTest.length(), sizeof(local));
}
You can do this with inline Flash Strings using FSTR_ARRAY()
:
FSTR_ARRAY(buffer, "text");
Is roughly equivalent to:
char name[] = "text";
Except the buffer is word aligned, so sizeof(name) may differ.
Macros¶
-
FS_PTR
(str)¶ Define an inline String and return a pointer to it.
- Note
- The rather obscure
asm
statement is required to prevent the compiler from discarding the symbol at link time, which leads to an ‘undefined reference’ error
-
FS
(str)¶ Define an inline FSTR::String and return it as a copy.
Example:
Serial.println(FS("This is a Flash String"));
-
DECLARE_FSTR
(name)¶ Declare a global FSTR::String& reference.
- Note
- Define the FSTR::String object using DEFINE_STR()
- Parameters
name
:
-
DEFINE_FSTR
(name, str)¶ Define a FSTR::String object with global reference.
Example:
- Parameters
name
: Name of FSTR::String& reference to definestr
: Content of the FSTR::String
DEFINE_FSTR(test, “This is a test\0Another test\0hello”)
The data includes the nul terminator but the length does not.
-
DEFINE_FSTR_LOCAL
(name, str)¶ Like DEFINE_FSTR except reference is declared static constexpr.
-
DEFINE_FSTR_DATA
(name, str)¶ Define a FSTR::String data structure.
- Parameters
name
: Name of data structurestr
: Quoted string content
-
LOAD_FSTR
(name, fstr)¶ Load a FSTR::String object into a named local (stack) buffer.
Example:
DEFINE_FSTR(globalTest, "This is a testing string") ... LOAD_FSTR(local, globalTest) printf("%s, %u characters, buffer is %u bytes\n", local, globalTest.length(), sizeof(local));
-
FSTR_ARRAY
(name, str)¶ Define a flash FSTR::String and load it into a named char[] buffer on the stack.
- Note
- Equivalent to
char name[] = "text"
except the buffer is word aligned. Faster than using a temporary Wiring String and avoids using the heap. - Parameters
name
: Name of char[] bufferstr
: Content of FSTR::String
-
IMPORT_FSTR
(name, file)¶ Define a FSTR::String containing data from an external file.
- See
- See also
IMPORT_FSTR_DATA
- Parameters
name
: Name for the FSTR::String objectfile
: Absolute path to the file containing the content
-
IMPORT_FSTR_LOCAL
(name, file)¶ Like IMPORT_FSTR except reference is declared static constexpr.
-
FSTR_TABLE
(name)¶ declare a table of FlashStrings
- Parameters
name
: name of the table
Declares a simple table. Example:
DEFINE_FSTR(fstr1, "Test string #1"); DEFINE_FSTR(fstr2, "Test string #2"); FSTR_TABLE(table) = { &fstr1, &fstr2, };
Table entries may be accessed directly as they are word-aligned. Examples:
debugf("fstr1 = '%s'", FSTR::String(*table[0]).c_str()); debugf("fstr2.length() = %u", table[1]->length());
String Class¶
-
class
String
: public FSTR::Object<String, char>¶ describes a counted string stored in flash memory
Public Functions
-
size_t
size
() const¶ Get the number of bytes used to store the String.
- Note
- Always an integer multiple of 4 bytes
-
flash_string_t
data
() const¶ Get a WString-compatible pointer to the flash data.
-
bool
equals
(const char *cstr, size_t len = 0) const¶ Check for equality with a C-string.
- Note
- loads string into a stack buffer for the comparison, no heap required
- Parameters
cstr
:len
: Length of cstr (optional)
- Return Value
bool
: true if strings are identical
-
bool
equals
(const String &str) const¶ Check for equality with another String.
- Parameters
str
:
- Return Value
bool
: true if strings are identical
-
bool
operator==
(const char *str) const¶
-
bool
operator!=
(const char *str) const¶
-
operator WString
() const¶
-
bool
equals
(const WString &str) const¶
-
bool
equalsIgnoreCase
(const WString &str) const¶
-
bool
operator==
(const WString &str) const¶
-
bool
operator!=
(const WString &str) const¶
-
StringPrinter
printer
() const¶ Supports printing of large String objects.
Avoids implicit String() cast when working with large FlashStrings:
IMPORT_FSTR(largeString, PROJECT_DIR "/files/large-text.txt"); Serial.println(largeString.printer());
-
size_t
printTo
(Print &p) const¶
-
Iterator
begin
() const
-
Iterator
end
() const
-
size_t
length
() const Get the length of the content in elements.
-
int
indexOf
(const ValueType &value) const
-
char
valueAt
(unsigned index) const
-
char
operator[]
(unsigned index) const Array operator[].
-
size_t
elementSize
() const
-
size_t
read
(size_t index, char *buffer, size_t count) const¶ Read content into RAM.
- Parameters
index
: First element to readbuffer
: Where to store datacount
: How many elements to read
- Return Value
size_t
: Number of elements actually read
-
size_t
read
(size_t offset, void *buffer, size_t count) const Read contents of a String into RAM.
- Parameters
offset
: Zero-based offset from start of flash data to start readingbuffer
: Where to store datacount
: How many bytes to read
- Return Value
size_t
: Number of bytes actually read
-
size_t
readFlash
(size_t index, char *buffer, size_t count) const¶ Read content into RAM,using
flashmem_read()
- Parameters
index
: First element to readbuffer
: Where to store datacount
: How many elements to read
- Return Value
size_t
: Number of elements actually read
-
size_t
readFlash
(size_t offset, void *buffer, size_t count) const Read contents of a String into RAM, using flashread()
PROGMEM data is accessed via the CPU data cache, so to avoid degrading performance you can use this method to read data directly from flash memory. This is appropriate for infrequently accessed data, especially if it is large. For example, if storing content using
IMPORT_FSTR
instead of SPIFFS then it is generally better to avoid contaminating the cache.- See
- See also
FlashMemoryStream
class. - Parameters
offset
: Zero-based offset from start of flash data to start readingbuffer
: Where to store datacount
: How many bytes to read
- Return Value
size_t
: Number of bytes actually read
-
template <class ObjectType>
constexpr const ObjectType &as
() const Cast to a different object type.
- Note
- example:
fstr.as<Array<int>>();
-
bool
isCopy
() const
Public Members
-
uint32_t
flashLength_
Public Static Functions
-
static const String &
empty
() Return an empty object which evaluates to null.
-
size_t