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