Constant Joy (2)

The const keyword in C is a useful tool with different meanings in different contexts. In my first article, I looked at const applied to global variables and now I will consider const applied to local variables.
In this function, Double, the variable c_local is a local variable.
1
2
3
4
5
int Double( short x )
{
int const c_local = 2;
return c_local * x;
}
The variable c_local is local to the function Double in the sense that it is accessible only to other code within the same function. We could have other variables also called c_local in other functions, and they would all be separate variables.
The const qualifier means that a variable does not change within its lifetime. For a global variable, its lifetime is the duration of the main function and it never changes. For an automatic (auto) local variable, its lifetime is only the duration of its containing function. Each time the function runs, that const auto variable could have a different value. This means that the initial value for a const global has to be known at compile time, but the initial value for a const auto can be determined at run-time, as in the function scale.
1
2
3
4
5
int Scale( short x )
{
int const c_local = Log2( x );
return c_local * x;
}
A local variable does not have to be an auto variable, we can also have a static local variable, whose lifetime is that of main and whose initializer must be known at compile time. We could change Double to use a static local const variable.
1
2
3
4
5
int Double( short x )
{
static int const c_local = 2;
return c_local * x;
}
When the initializer is known at compile time, we can freely choose between using a static and an auto const. This choice is interesting in the embedded domain, where a static const will typically be read direct from flash and never copied to RAM.
Consider a large function with a local look-up table.
1
2
3
4
5
void Large( void )
{
/* static */ int const c_lookup[128] = {/* 128 values */};
/* Lots of code */
}
If c_lookuip is an auto variable, the compiled code must, each time Large starts to run, copy the flash initializer for c_lookup to the stack.This is going to take significant time. In contrast, if we uncomment the static keyword to make this a static variable, the compiled code can simply read directly from c_lookup in flash without doing any preliminary copy. This presents an interesting tradeoff:
If there are lots of read accesses that would be cache misses with c_lookup in slow, flash memory, Large will be faster with an auto c_lookup on the stack.
If there are few read accesses that would be cache misses, Large would be faster keeping c_lookup in flash and saving the time to copy it to the stack.
I have to confess to learning this lesson the hard way. I cleverly made a large const auto array static to save the copy to stack, only to make the function slower.
In the next article, I will look at using the const keyword with pointers, to declare that the pointed-to object is const, rather than the pointer variable itself.