Using Standard C and C++ Libraries

I’ve realized that not everyone is aware that most of the standard C and C++ libraries are available for your use on the Particle products, simply by including a header. You don’t have to add a library or anything! For example:

// Sample code demonstrating use of C/C++ standard libraries

// Common C standard library headers. Only include the ones you need!
#include <ctype.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

// Common C++ standard library headers. Only include the ones you need!
#include <bitset>
#include <deque>
#include <list>
#include <map>
#include <set>

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

void loop() {

    // Most of the Standard C libary is supported
    // https://en.wikipedia.org/wiki/C_standard_library

    // If you're using Particle Dev (the Atom-based IDE) with cloud compile, if you
    // attempt to use a standard library function that's not supported (say, time()),
    // you may get no compile errors but the build will fail with a
    // Build did not produce binary error. It's actually an unresolved link error,
    // but the error does not show up (as of 2016-03-04, at least).

    {
        // #include <string.h>
        // https://en.wikipedia.org/wiki/C_string_handling
        // http://www.gnu.org/software/libc/manual/html_node/String-and-Array-Utilities.html
        char *s1 = "hello world";
        Serial.printlnf("strlen(%s)=%d", s1, strlen(s1)); // 11

        char buf[16];
        if (strlen(s1) < sizeof(buf) - 1) {
            strcpy(buf, s1);
            Serial.printlnf("after strcpy, buf=%s", buf);
        }

        char *cp = strchr(s1, 'o');
        if (cp != NULL) {
            Serial.printlnf("strchr(s1, 'o')=%s", cp); // o world
        }

        cp = strstr(s1, "or");
        if (cp != NULL) {
            Serial.printlnf("strstr(s1, \"or\")=%s", cp); // orld
        }

        Serial.printlnf("strcmp(s1, buf)=%d", strcmp(s1, buf)); // 0

        // Zero out a block of memory
        bzero(buf, sizeof(buf));
        Serial.printlnf("after bzero buf[0]=%d buf[1]=%d buf[2]=%d", buf[0], buf[1], buf[2]);
    }

    {
        // #include <math.h>
        // https://en.wikipedia.org/wiki/C_mathematical_functions#Overview_of_functions
        // http://www.gnu.org/software/libc/manual/html_node/Mathematics.html
        // http://www.gnu.org/software/libc/manual/html_node/Arithmetic-Functions.html
        Serial.printlnf("pow(2, 3)=%lf", pow(2, 3)); // 8.0

        Serial.printlnf("sqrt(400)=%lf", sqrt(400)); // 20.0

        Serial.printlnf("sin(3.14)=%lf", sin(M_PI)); // 0.0

        Serial.printlnf("floor(5.9)=%lf", floor(5.9)); // 5.0

        Serial.printlnf("abs(-200)=%d", abs(-200)); // 200
    }
    {
        // #include <stdio.h>
        // https://en.wikipedia.org/wiki/C_file_input/output

        // building strings with sprintf
        // http://www.gnu.org/software/libc/manual/html_node/Formatted-Output.html
        const char *name = "John";

        char buf[32];
        snprintf(buf, sizeof(buf), "Hello %s", name); // Hello John
        Serial.printlnf("snprintf hello string=%s", buf);

        // http://www.gnu.org/software/libc/manual/html_node/Formatted-Input.html
        int a = 0, b = 0, c = 0;
        const char *input = "12,34,5678";
        if (sscanf(input, "%d,%d,%d", &a, &b, &c) == 3) {
            Serial.printlnf("sscanf a=%d b=%d c=%d", a, b, c);
        }
        else {
            Serial.printlnf("sscanf not enough parts");
        }

    }

    {
        // #include <stdlib.h>
        // https://en.wikipedia.org/wiki/C_string_handling#stdlib.h

        // Number parsing
        Serial.printlnf("atoi(\"5678\")=%d", atoi("5678"));

        Serial.printlnf("atof(\"56.789\")=%f", atof("56.789"));

        // Hexadecimal conversion
        Serial.printlnf("strtoul(\"100\", NULL, 16)=%d", strtoul("100", NULL, 16)); // 256

        // qsort (and bsearch) work
        int vals[] = { 5, 3, 6 };
        qsort(vals, sizeof(vals) / sizeof(int), sizeof(int), intCompare);
        Serial.printlnf("after qsort vals[0]=%d vals[1]=%d vals[2]=%d", vals[0], vals[1], vals[2]);
    }

    {
        // #include <ctype.h>
        // https://en.wikipedia.org/wiki/C_character_classification

        // Character classification
        char c = 'A';
        Serial.printlnf("isalpha('A')=%d", isalpha(c)); // 1

        Serial.printlnf("isdigit('A')=%d", isdigit(c)); // 0
    }

    {
        // #include <time.h>
        // https://en.wikipedia.org/wiki/C_date_and_time_functions

        // Time and Date handling

        // Note: time() is not supported! Use the Time class instead.
        // time(&timeNow);
        time_t timeNow = (time_t) Time.now();

        Serial.printlnf("time=%ld", timeNow);

        // Using the Paricle Time class is much easier, but the functions below do work
        // https://docs.particle.io/reference/firmware/core/#time

        // Also, the stdclib doesn't know your timezone, so localtime actually behaves
        // like gmtime (UTC time +000).
        struct tm *tmNow;
        tmNow = localtime(&timeNow);

        // Note: tm_mon is 0-11 not 1-12!
        // Also tm_year will be 116 for 2016. Add 1900 for normal use.
        Serial.printlnf("tm_year=%d tm_mon=%d tm_mday=%d", tmNow->tm_year, tmNow->tm_mon, tmNow->tm_mday);

        // Time.format uses strftime internally and may be easier in some cases
        char buf[32];
        strftime(buf, sizeof(buf), "%Y-%m-%d %H:%m:%S", tmNow);
        Serial.printlnf("strftime=%s", buf);
    }

    // The Standard C++ Library is supported as well
    // https://en.wikipedia.org/wiki/C%2B%2B_Standard_Library

    {
        // std::bitset
        // #include <bitset>
        // http://en.cppreference.com/w/cpp/utility/bitset

        // This class is handy if you need to maintain binary bit flags. test
        // values, do logical and, or, etc.. Lots of useful functions and efficient.
        std::bitset<8> b(42);          // [0,0,1,0,1,0,1,0]
        Serial.printlnf("bitset any=%d all=%d test[0]=%d", b.any(), b.all(), b.test(0));
    }

    {
        // std::deque
        // #include <deque>
        // http://en.cppreference.com/w/cpp/container/deque

        // Handy double-ended queue
        std::deque<int> q;

        q.push_back(1234);
        q.push_back(9999);

        Serial.printlnf("dequeue %d", q.front());
        q.pop_front();
    }

    {
        // std::list
        // #include <list>
        // http://en.cppreference.com/w/cpp/container/list

        // Doubly-linked list. A list of str::string strings, in this cases

        std::list<std::string> list;
        list.push_back("hello");
        list.push_back("world");

        for (std::list<std::string>::const_iterator ci = list.begin(); ci != list.end(); ++ci) {
            Serial.printlnf("list %s", (*ci).c_str());
        }
    }

    {
        // std::set
        // #include <set>
        // http://en.cppreference.com/w/cpp/container/set

        // A sorted set of values, integers, in this case
        std::set<int> set;

        set.insert(10);
        set.insert(333);
        set.insert(1);

        for (std::set<int>::const_iterator ci = set.begin(); ci != set.end(); ++ci) {
            Serial.printlnf("set %d", *ci);
        }
    }

    // There are a bunch more, but I got tired of writing examples.

    // std::regex
    // I was unable to get this to work, but I didn't spend that long trying. Would have been useful!


    delay(30000);
}

// Comparison function for qsort or bsearch
int intCompare (const void *pa, const void *pb)
{
    int a = *(const int *)pa;
    int b = *(const int *)pb;

    if (a < b)
        return -1;
    else
    if (a > b)
        return +1;
    else
        return 0;
}

And the output:

strlen(hello world)=11
after strcpy, buf=hello world
strchr(s1, 'o')=o world
strstr(s1, "or")=orld
strcmp(s1, buf)=0
after bzero buf[0]=0 buf[1]=0 buf[2]=0
pow(2, 3)=8.000000
sqrt(400)=20.000000
sin(3.14)=0.000000
floor(5.9)=5.000000
abs(-200)=200
snprintf hello string=Hello John
sscanf a=12 b=34 c=5678
atoi("5678")=5678
atof("56.789")=56.789000
strtoul("100", NULL, 16)=256
after qsort vals[0]=3 vals[1]=5 vals[2]=6
isalpha('A')=1
isdigit('A')=0
time=1457130729
tm_year=116 tm_mon=2 tm_mday=4
strftime=2016-03-04 22:03:09
bitset any=1 all=0 test[0]=0
dequeue 1234
list hello
list world
set 1
set 10
set 333
6 Likes