PString

A Lightweight String Class for Formatting Text

Note: PString 3 is now Arduino 1.0 compatible.

Since Print was introduced with Arduino 0012, several classes, including HardwareSerial, LiquidCrystal, Ethernet Client/Server, and my own NewSoftSerial, have been written to leverage its text rendering engine.  But getting formatted text to output devices not in this short list still requires either writing custom code or turning to expensive alternative solutions like sprintf().

PString (“Print-to-String”) is a new lightweight Print-derivative string class that renders text into a character buffer. With PStrings, you can use the Print renderer for any device, even those that do not directly support Print-style text formatting, by first “printing” to a string.

In its simplest use case, you deploy an “on-the-fly” constructor to format text:

char buffer[30];
#define pi 3.14159

PString(buffer, sizeof(buffer), pi);

This code uses Print’s float rendering functions to generate the string equivalent of pi into buffer.

Since PString inherits from Print, PString objects can do everything that other Print-derived classes do:

char buffer[50];
PString mystring(buffer, sizeof(buffer));
char name[] = "Joe";
int age = 45;

mystring.print("Hi, my name is ");
mystring.print(name);
mystring.print(" and I am ");
mystring.print(age);
mystring.println(" years old.");

This generates the expected sentence in buffer the same as if you had printed to the Serial port.

Other member functions

PString is a fairly minimal string class. It can report its length and capacity and give const access to its internal string buffer:

Serial.print(str.length());
Serial.print(str.capacity());
Serial.print(str);

You can reuse a string by calling its begin() function. This effectively resets the position in the buffer where the next printed text will go:


str.print("Hello");
str.begin();
str.print("World");
// str contains "World" here

Operators

PString provides three operators for assignment, concatenation, and equivalency test:

char buffer[20];
PString str(buffer, sizeof(buffer));
str = "Yin"; // assignment
str += " Yang"; // concatenation
if (str == "Yin Yang") // comparison
{
  Serial.println("They are equal!");
}

Runtime safety

PStrings do not “own” their own buffers. Instead, they rely on preallocated static buffers that are passed in at the point of construction. PStrings never allocate memory dynamically, even when the result of a print(), assignment, or concatenation operation would seem to exceed the current buffer’s size. In these cases, the excess data is simply discarded and the string correctly terminated.

Because of these constraints, PStrings can make three key guarantees:

  • they will never cause a buffer overflow
  • a string’s buffer will always be valid memory, i.e. the original buffer
  • buffers will always contain valid (i.e. NULL-terminated) C string data.

Download

The latest version of PString is PString3.zip.

Revision History

Version 1 – initial release
Version 2 – include support for inline renderings with modifiers HEX, OCT, etc. (and eventually float precision)
Version 3 – Arduino 1.0 compatibility

Resource Consumption

PString objects consume 8 bytes of memory during their lifetimes. Depending on what features are used, #including the PString library usually adds only 100-600 bytes to a program’s size.

All input is appreciated.

Mikal Hart

Page last updated on January 28, 2012 at 12:38 am
19 Responses → “PString”

  1. Anonymous

    2 years ago

    Hi … I was testing your library and the following code fails in one part!

    ———-
    #include

    char localBuffer[25];
    PString locBuf(localBuffer, sizeof(localBuffer));

    void setup() {
    Serial.begin(9600);
    locBuf.begin();
    }

    void loop() {
    locBuf = byte(70); // F
    locBuf += byte(97); // a
    locBuf += byte(105); // i
    locBuf += byte(112); // l
    Serial.print(locBuf); // prints out “Fail” OK
    Serial.print(locBuf.length()); // prints 0 -> FAIL shoud be 4
    }
    ———

    Do you have any idea why?

    thx!


  2. Mikal

    2 years ago

    Hmmm… on my Arduino, using 0017, this prints

    Faip4Faip4

    repeatedly, which is exactly what I would expect. If yours prints “Fail0″, I don’t understand where the ’0′ comes from — or the ‘l’ for that matter! :)

    Mikal


  3. Anonymous

    2 years ago

    thx a lot… this is not the full code, I just simplified it!
    i’m using your library 2 make a “sensor package” 4 XBee transmission…
    I miss calculated the “l” sry bout that!
    it’s possibly some reference problem! i’ll try 2 figure it out!
    BTW Great job on the library!


  4. Jonathan Starke

    2 years ago

    Thank you thank you, you saved me a lot of frustration
    Thnx
    Jonathan


  5. Mark Kieling

    1 year ago

    Mikal, there is no call to va_end in your library. It is my understanding that a call to va_start must be balanced with a call to va_end. Is this not the case?


  6. Mikal

    1 year ago

    Thanks, Mark. I *think* it’s harmless in this case, but you’re quite right. I should put that in the next edition. Thanks.

    Mikal


  7. Frikosal

    1 year ago

    Thanks !!

    May I suggest to change slightly the example ?

    str.print(“The value of PI is “);
    str.print(PI,4);

    The “,4″ to indicate the number of decimal places would be useful for people like me.


  8. Mikal

    1 year ago

    @Frikosal–

    Good idea!

    Thanks.


  9. robbok

    1 year ago

    Hey Mikal, just a note of thanks for creating this library. It literally saved my life with the Sparkfun 16×2 LCD. I was going out of my mind not being able to print numbers or easily concatenate strings and numbers. You’re a lifesaver!


  10. Mikal

    1 year ago

    @robbok,
    :)


  11. Carl Nobile

    8 months ago

    The format() method sounded like just what I needed, however, it doesn’t seem to work with floats. Below is what I see on the serial monitor:

    str.format(“CM: %04ld, SD: %6.2f, IN: %04ld, SD: %6.2f\n”,
    cmMsec, cmSD, inMsec, inSD);

    gives me this:

    CM: 0159, SD: ?, IN: 0062, SD: ?

    I think it may be the underlying implementation of vsnprintf. Also the final /n is not recognized at all as I am getting the typical staircase effect on the serial monitor.

    I have been looking for documentation on the Arduino implementation of there C/C++ libs, do you know if they exist and if so where to find them?

    Thanks, Carl


  12. Mikal

    7 months ago

    Yeah, unfortunately the tiny arv-gcc implementation of Xprintf() doesn’t support %f floating point conversions. Too bad!

    Mikal


  13. Christoph

    4 months ago

    Hi, I use PString in a few of my projects. After installing Arduino 1.0 I realized that PString doesn’t work with the new Arduino 1.0 standard.

    an update for PString that can be used with the new version would be very much appreciated

    Chris


  14. Mikal

    3 months ago

    @Christoph,

    PString has now been updated to support Arduino 1.0! :)


  15. Ria

    2 months ago

    hi am having a problem on how to read data from xbee through arduino am new to this . i have downloaded the library of xbee

    my transmitter xbee is sending analog data from my accelerometer X,Y,Z into packets i understand my packets when i use X-ctu and it seems right .

    but could you tell me how to program my Arduino so it can understand my packets when i connect my receiver to Arduino ??

    I NEED The CODE ?
    please help am stuck for week !!

4 Trackbacks For This Post
  1. Introducing PStrings « Arduiniana

    [...] Check out the new PString class. [...]

  2. ka1kjz.com » Twittering Arduino Completed

    [...] actual text for the tweet, the Arduino has very limited string manipulation functions.  But the PString library by Mikal Hart proved to be just what I [...]

  3. Arduino net connected clock tells weather not time

    [...] third party libraries were used; PString to handle parsing the incoming website, Flash for memory management, and Streaming for easier [...]

  4. Arduino and Windows HyperTerminal | Binglong's space

    [...] is a text string with an ending CR(Carriage Return, 0x0d), so is any reply from the board. Actually PString can be used to format the reply (or an active notification from board) easily. Messenger can be [...]

Leave a Reply