const

It took me a long time to understand that the const qualifier in C is overloaded. There was no const when I first learned C. It was introduced in the C90 standard. It was copied from C++, although the meaning of const is subtly different in the two languages.

The first meaning of const in C is to use it to qualify a variable definition. If you do that, it means that the variable can not be changed; it is immutable. It can have an initializer but will never have another value. A global or static const variable may be placed in read-only memory.

The second meaning is to use it to qualify a pointer. In this usage it means that the program may not change the value being pointed to by using the pointer. However, it does not mean that that value is immutable, as it may be changed by a different pointer, or by a function call, or by casting away the const qualifier.

The first meaning of const has a real effect on the program. A variable declared const may be compiled differently from a variable which is not declared const. The second meaning of const, on the other hand, is, in effect, compiler-enforced documentation. The compiler will issue an error if an attempt is made to change a value using a const qualified pointer, but declaring such a pointer will not change the generated code.

Although const qualified pointers are just documentation, in practice they are used far more often than const variables. When the C90 standard came out and C compilers started supporting const, programmers spoke of const-poisoning: the feeling that once you use the const qualifier anywhere, it spread throughout your program as it had to be tracked through all assignments and function calls to avoid compiler warnings. Adding const-poisoning to a program does not make it any more correct or reliable. It’s just documentation, albeit documentation that the compiler enforces.

One can imagine a range of different types of documentation which it might be nice to have the compiler enforce. Perhaps it would be useful to know the alignment of a generic pointer, or to know that this char* pointer points to a null terminated string while that one points to a block of arbitrary bytes. A program can use a typedef to indicate the intended meaning of some value, but a pointer to one typedef can be assigned to a pointer to a different typedef with no warning if the underlying types happen to be the same. Why do we get compiler warnings for const pointers but not for typedef pointers? It’s because const was added to the type system, whereas typedef, despite its name, is merely an aliasing mechanism, and is not part of the type system at all.

It did not have to be this way. It would have been possible to make const a storage specifier, like static, rather than a type qualifier. It would have simply meant that the variable was immutable. The address of a const int would have type int * rather than const int *.

The C90 standard introduced one other type qualifier: volatile (in fact, the standard introduced the whole idea of type qualifiers). Unlike const, the standard did not define the meaning of a volatile qualified pointer. The address of a volatile variable has a volatile qualified pointer type, but the standard never said what the compiler should do with such a type. It only says that any access to a volatile variable must be through an lvalue with the volatile qualifier.

The C99 standard adds a third type qualifier, restrict, which is another can of worms.

In retrospect I think that adding the const qualifier to the type system was a mistake. It lets the compiler enforce a specific type of documentation but doesn’t let the program define the types of documentation that it cares about. The documentation is not reliable as programs can cast away the qualifier, and indeed the standard requires basic functions like strchr to do exactly that.

If you want the compiler to be able to check type attributes, then give the language a way to define the attributes that matter to a particular program. If you want to compiler to be able to put a variable in a specific type of storage, such as a read-only data section, then use a storage specifier. There is no need to mix the two ideas.

3 Comments »

  1. regehr said,

    October 22, 2010 @ 9:24 am

    The “two meanings” of const aren’t quite as straightforward as you suggest. A “const volatile” variable is one that may change unexpectedly, but that may not be written to.

  2. Ian Lance Taylor said,

    October 22, 2010 @ 10:06 pm

    Thanks for the comment. I would say that const volatile is a third case which I didn’t consider. I think it’s significantly less common than the other uses.

  3. Why would you use the keyword const if you already know variable should be constant? - ExceptionsHub said,

    December 19, 2017 @ 7:49 am

    […] is a good explanation from Ian Lance Taylor (who worked on gcc and gold […]

RSS feed for comments on this post · TrackBack URI

Leave a Comment

You must be logged in to post a comment.