The simplest way to read and write const declarations correctly is to use an unconventional style
When support for the const qualifier appeared in compilers some 20 years ago, I learned to place it as most programmers do: to the immediate left of the type that it modifies. That is, when I wanted to declare p as a pointer to a constant character, I wrote the declaration as:
const char *p;
as just about everyone else did.
As I grew to understand the const qualifier better, I started to encourage other programmers to use it, which I did by using const whenever appropriate in my writing and in my lectures. Still, many programmers seemed less than enthusiastic about using const. I started asking programmers why they were reluctant to use const. Most said they just didn’t understand it. They knew they could place const at different points within a declaration, and they just didn’t understand the consequences of the different placement options. For example, const in const char *p; modifies the char to its immediate right (it declares p as a pointer to a const char).
Does that mean that the const in char const* p; modifies the pointer operator to its immediate right (it declares p as a const pointer to a char)? (Answer: No.)
In the mid-1990s, it occurred to me that it might be easier for programmers to understand const if they learned to apply this fairly simple rule: When writing a declaration, place const to the immediate right of the part of the type that you want to be const. When reading that declaration, read const just before you read the thing to its immediate left. For example, to declare p as a pointer to const char, write:
char const *p;
To read it aloud, just read it from right to left, as “p is a pointer to a const char.” To declare p as a const pointer to char, write:
char *const p;
To read it aloud, again just read it from right to left.
In the years that I’ve been using and teaching this style for placing const in declarations, I received a lot of positive feedback that using this style does indeed help. Unfortunately, the converts represent what appears to be a distinct minority of C and C++ programmers. Most C and C++ programmers simply won’t do it. Moreover, they won’t even try it.
When I ask programmers why they won’t try it, they often tell me, “It’s not conventional” or, “Hardly anybody does it that way,” to which I offer the following response.
For the last six to eight years, I’ve been posing the following query to my lecture audiences. Given these declarations in the conventional style:
typedef char *ntcs; const ntcs s;
what is it about s that’s const? Is it (a) the character, or (b) the pointer, or (c) both? (The answer appears at the end of this article.) I’ve posed this question to thousands of programmers and only about 40% get it right. The rest either get it wrong or are unable or unwilling to hazard a guess. At the same time, well over 90% of these programmers reported using the conventional style for placing const.
So, when someone tells me they won’t use it because it’s not conventional, my response is that, in this case, conventional isn’t working. Maybe it’s time to try something else.
Other times, when I ask programmers why they won’t try it, they tell me something like, “It won’t work. It’ll confuse people.” When I ask, “Have you tried it, or do you know someone who’s tried it and been confused by it?” the answer is invariably, “No.” When I ask, “How do you know it won’t work if you won’t try it?” too often the answer is something like, “It’s obvious that it won’t.” Not to me it isn’t.
Of course, there are those programmers who use the conventional style and understand declarations well enough to correctly interpret:
const ntcs s;
as well as more complex declarations. I can understand why they see no need to adopt a different style. Nonetheless, some programmers who don’t need to switch styles for themselves have done it to help coworkers who’ve struggled with const, and reported positive results.
The keyword const is a very useful feature of C and C++, especially for writing embedded systems. The keyword volatile is also useful and follows rules that are nearly identical to the rules for const. Using const and volatile appropriately is a good thing, and programmers ought to be encouraged to do it. Unfortunately, the conventional style for placing const in declarations doesn’t seem to help much.
More than a decade ago, I started using and recommending the alternative style for placing const in declarations. While I know this style takes a little getting used to, I’ve had many programmers try it and tell me it helped them use const more effectively.
By the way, the answer to my “What is it about s that’s const?” question is (b). The declaration:
const ntcs s;
declares s as a const pointer to char.
Dan Saks is a teacher and writer on C++. A modified version of this article originally appeared in EE Times in December 2008.