Wednesday, 7 November 2018

sizeof operator in C and C++ should be better known

Having seen some code examples on the Internet where sizeof should be used, I thought I'd offer a short reminder of a couple of useful cases:

1. A EPROM burner program to run on Arduino where the data was embedded as a byte array in the sketch which is then compiled and downloaded to run:

What was written:

const int progSize = 1024;
const byte hexProg[progSize] = { ... };
...
for (i = 0; i < progSize; i++) {
...
}

What should have been written:

const byte hexProg[] = { ... };
...
for (i = 0; i < sizeof(hexProg); i++) {
...
}

This has the advantage of automatically adapting to the number of bytes that actually need to be programmed instead of always 1024.

2. An Arduino program to test a LCD display:

What was written:

char row1[] = "I'm Arduino";
...
for (int positionCounter1 = 0; positionCounter1 < 26; positionCou
nter1++) {


This prints junk after the greeting because it strays past the end of the string, which is also a security hazard.

What should have been written:

for (int positionCounter1 = 0; positionCounter1 < sizeof(row1) - 1; positionCounter1++) {

The - 1 is to not print the NUL byte at the end of the string. A reminder, if the string is say UTF-8, sizeof gives the number of bytes in the string, not the number of characters. But usually the number of bytes is what you want.

Also do not make this mistake:

char *row1 = "I'm Arduino";

In this case sizeof(row1) will be sizeof(char *) on the machine, not the length of the phrase I'm Arduino.

A couple of other idioms.

Getting the number of elements in an array:

int divisors[] = { 2273, 2145, 2025, 1911, ... };
const int ndivisors = sizeof(divisors)/sizeof(int);

Or even better:

const int ndivisors = sizeof(divisors)/sizeof(divisors[0]);

which means you can change the type of the divisors array to be other than an int without changing the second line.

Allocating the right amount of memory from heap:

double *readings;
...
readings = malloc(NREADINGS * sizeof(double));

And a reminder, sizeof is a compile-time operator, so there is no runtime cost to using it. If the expression provided to sizeof cannot be evaluated at compile-time, the compiler will tell you.