Using Standard C and C++ Libraries


#1

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

#2

Great for all to know.

The Particle Time Library is already “included” in the base IDE. Look out for subtle differences in their respective implementations.

Also, String class…


#3

9 posts were split to a new topic: Using qsort to average readings


#4

A post was merged into an existing topic: Using qsort to average readings


#5

Many users seem to be having issues with importing std C++ libraries.

In my case:

#include <map>

Resulting error:

/usr/local/gcc-arm-embedded-gcc-arm-none-eabi-4_8-2014q2-20140609-linux-tar-bz2/arm-none-eabi/include/c++/4.8.4/bits/stl_tree.h:735:25: error: macro "swap" requires 2 arguments, but only 1 given
       swap(_Rb_tree& __t);   

I was able to fix the issue with:

#unset 

I’m using quite a few libraries im my project so i’m not sure if there is a conflict of some type there, but my code definitely does not define swap anly place.


#6

The #define SWAP() is in the mbedtls and mbeddes crypto libraries, so not in your code.


Photon Maker Kit - DS18B20 - temperature sensing issues/questions
#7

Thanks for the reply @bko. I’m not including those libraries in my code. Are they included in the particle IDE automatically?

I aso have an issue with std::string:

#include <string>
std::string

Throws not found in name space errors… I’ve been using the particle String type instaed, but i thought it was strange…


Using qsort to average readings
#8

There are several libraries that do have this same bad habit to define macros for functions.
Adafruit_GFX is one of these (IMHO) badly designed libraries - if you revealed what libs you’re using, we’d not need to guess which one is causing this for you :wink:

But if library creators at least used the otherwise common practice to have macros all capitals like SWAP() instead of swap() that issue would not be present.
So the only way to get around this (without having to wait for the libs to get “corrected”) is to use #undef or #unset.

And for library creators: “If you #define macros, make the names unique to prevent such issues!”

BTW: #include <string> does work just fine for me.
Showing a minimal code that exhibits that error would be good for us to be able to test your assertion.