Additional standard functions
The C “standard” libraries include a number of functions not featured by the main Arduino documentation. They are listed here with short notes on their usage.
It is also worth mentioning that there are some synonyms for integer data types that are often used in sample code. After all, you might want to declare a 16 bit int that will still be 16 bits if the code is compiled for a 32 bit Arduino. You can be specific with int8_t, int16_t, int32_t and int64_t where the number defines the number of bits used for a signed integer type. Similarly, uint8_t, uint16_t, uint32_t and uint64_t define the bit length of unsigned integer types. The type size_t is the unsigned integer type returned by the sizeof() function although the bit width is system dependent.
There are also some useful macros in the form INTn_MIN, INTn_MAX and UINTn_MAX that define the minimum and maximum values that can be stored in a specific int type where n is the relevant number of bits. These can be handy for initialising variables at one extreme or the other.
The limits.h library also has definitions for values such as INT_MAX or LONG_MIN and these values are adjusted for the appropriate board at compile time.
<string.h>
This library contains many useful functions for manipulating char arrays. Many of these together with number conversion functions from stdlib.h are re-packaged by the Arduino String object.
char *strcpy(aStr, bStr) | copies string bStr to string aStr, returns a pointer to aStr. |
char *strncpy(aStr, bStr, n) | copies n chars from string bStr to string aStr and pads with char ‘\0’ if bStr has less than n chars. |
char *strcat(aStr, bStr) | concatenates string bStr to the end of aStr, returns a pointer to aStr. This is managed by inserting the chars in bStr from the terminating null char in aStr. The char array containing aStr must be large enough to accept the string bStr. |
char *strncat(aStr, bStr, n) | concatenates up to n chars from bStr to aStr. terminates aStr with ‘\0’ |
int strcmp(aStr, bStr) | compares aStr to bStr. If aStr < bStr, returns a value < 0, returns 0 if aStr == bStr and returns a value > 0 if aStr > bStr |
int strncmp(aStr, bStr, n) | as above but only compares up to n chars |
char *strchr(aStr, bChr) | returns pointer to first occurrence of char bChr in string aStr or NULL |
char *strrchr(aStr, bChr) | returns pointer to last occurrence of char bChr in string aStr or NULL |
size_t strspn(aStr, bStr) | starting from the first char in aStr, returns the number of chars in aStr that can be found in bStr irrespective of order. |
size_t strcspn(aStr, bStr) | starting from the first char in aStr, returns the number of chars in aStr that are not found in bStr |
char *strpbrk(aStr, bStr) | returns a pointer to the first occurrence of any char in bStr in aStr or NULL |
char *strstr(aStr, bStr) | returns a pointer to the first occurrence of string bStr in aStr or NULL |
size_t strlen(aStr) | returns the length of aStr excluding the terminating null char |
char *strtok(aStr, delimStr) | repeated calls return the positions of one or more delimited string found in aStr (see below after math.h) |
void *memcpy(aStr, bStr, n) | copies n chars from bStr to aStr |
void *memmove(aStr, bStr, n) | as above but aStr and bStr can overlap in memory |
int memcmp(*a, *b, n) | compares first n bytes of memory location a with location b with same return values as strcmp() |
void *memchr(aStr, bChr, n) | returns pointer to first occurrence of char bChr in first n chars of string aStr or NULL |
void *memset(aStr, bChr, n) | sets first n chars of string aStr to value of char bChr |
<stdlib.h>
double atof(aStr) | converts string aStr to type double. Ignores leading whitespace, accepts a leading sign (optional) and ignores trailing characters not deemed part of double representation. |
int atoi(aStr) | As atof but converts string aStr to type int. |
long atoll(aStr) | As atof, converts string aStr to type long |
double strtod(aStr, char **endp) | converts numeric characters from the start of aStr to a double. If the char pointer endp is not null then it is set to the address of the first char in aStr that could not be included in the conversion. |
long strtol(aStr, char **endp, int base) | similar to strtod() but returns a long. In addition, the number base can be set to a value between 2 and 36. If base is 0 then the function expects the string aStr to indicate the base. A leading 0 indicates base 8, 0x hexadecimal with base 10 the default. |
unsigned long strtoul(aStr, char **endp, int base) | same as strtol but returns an unsigned long |
void *malloc(n) | returns a pointer to a new memory allocation n bytes long or NULL if no space available |
void *calloc(s, n) | returns a pointer to a new memory allocation with space for n elements of an array where each element is size s bytes. Returns NULL if requested space is not available |
void *realloc(void *p, s) | changes an existing memory allocation. |
void free(void *p) | deallocates memory identified by pointer p that must have been previously allocated by malloc(), calloc() or realloc() |
long labs(l) | returns absolute value of long l |
struct{ int quot; int rem } div_t div(int num, int denom) |
divides num by denom and returns the struct with the quotient in quot and the remainder in rem |
struct{ long quot; long rem; } ldiv_t ldiv(long num, long denom) |
as div() above but for long integers |
The malloc() and free() functions are not, what is called, re-entrant. If they are called directly or indirectly from an interrupt handler (as our Morse FiFo queue did) then they should not also be used concurrently from normal program functions.
<math.h>
Trigonometric function arguments express angles in radians and not degrees. All of the math.h library functions return a value of type double. Other “standard Arduino” math functions are documented in chapter 4 of this book.
asin(r) | sine-1 of angle r |
acos(r) | cosine-1 of angle r |
atan(r) | tan-1 of angle r |
atan2(x / y) | tan-1 of x / y |
sinh(r) | hyperbolic sine of r |
cosh(r) | hyperbolic cosine of r |
tanh(r) | hyperbolic tangent of r |
exp(x) | exponential function ex |
log(x) | natural logarithm of x |
log10(x) | base 10 logarithm of x |
ceil(x) | smallest integer not less than x, returned as double |
floor(x) | largest integer not greater than x, returned as double. Mind negative values of x |
fabs(x) | absolute value of x |
ldexp(x, n) | returns x multiplied by 2 raised to the power n |
frexp(x, int *e) | computes a fraction multiplied by a power of 2 that is equal to x. returns the fraction and writes the power of 2 to e(xponent) |
modf(x, double *i) | takes a double x, returns the fractional component while the integer component is stored in i |
fmod(x, y) | returns the remainder of x after being divided by y |
Some of these library functions are easier to describe in a few words than others. I think that strtok() needs a full explanation and a demo program. Many programming languages have something equivalent to a split() function that takes a string and returns an array of strings with each element from the original string delimited by some character. Aspects of that would represent something of a challenge in C but strtok() provides the required functionality in a style consistent with the language.
The function is passed a string to tokenise together with a string containing one or more delimiter. The function finds the first delimiter character in the string and replaces it with a null char. It then returns a pointer to the start of the string before the inserted null char. Subsequent calls to the same function cause the search for a delimiting char to start from the last one found. Each time the function finds a delimiter (or the string terminator) it does the substitution and returns a pointer to the start of the new string segment. Warning: this function makes changes to the original string.
A short demo code snippet should help with the explanation
template<class T> inline Print &operator <<(Print &obj, T arg) { obj.print(arg); return obj; }
char test[] = "Strange, that this is a test string";
char delim[] = ", "; // comma and space act as delimiters
void setup() {
Serial.begin(115200);
char *pc = strtok(test, delim);
while (pc != NULL) {
Serial << pc << '\n';
pc = strtok(NULL, delim);
}
Serial << "but now test is: " << test << '\n';
}
With the Serial Monitor showing:
Strange
that
this
is
a
test
string
but now test is: Strange
Notice that the second and subsequent calls to strtok() passes a NULL instead of the string that is being tokenised. This indicates to the function that it should continue with that last string and where it had previously left off.