While this can be used to declare constants, const in the C family of languages differs from similar constructs in other languages in that it is part of the type, and thus has complicated behavior when combined with pointers, references, composite data types, and type-checking.
A common example are read only registers within embedded systems like the current state of a digital input.
Such proactive use of const makes values "easier to understand, track, and reason about",[3] and it thus increases the readability and comprehensibility of code and makes working in teams and maintaining code simpler because it communicates information about a value's intended use.
[4] For simple non-pointer data types, applying the const qualifier is straightforward.
Thus: Following C++ convention of analyzing the type, not the value, a rule of thumb is to read the declaration from right to left.
For instance, in our example above, int const * can be read as a writable pointer that refers to a non-writable integer, and int * const can be read as a non-writable pointer that refers to a writable integer.
But putting const before what must be constant quickly introduces mismatches between what you intend to write and what the compiler decides you wrote.
Here are some examples: Bjarne Stroustrup's FAQ recommends only declaring one variable per line if using the C++ convention, to avoid this issue.
const can be declared both on function parameters and on variables (static or automatic, including global or local).
For this reason, some favor using const in parameters only for pass-by-reference, where it changes the contract, but not for pass-by-value, where it exposes the implementation.
In order to take advantage of the design by contract approach for user-defined types (structs and classes), which can have methods as well as member data, the programmer may tag instance methods as const if they don't modify the object's data members.
Applying the const qualifier to instance methods thus is an essential feature for const-correctness, and is not available in many other object-oriented languages such as Java and C# or in Microsoft's C++/CLI or Managed Extensions for C++.
Often the programmer will supply both a const and a non-const method with the same name (but possibly quite different uses) in a class to accommodate both types of callers.
The first, which applies only to C++, is the use of const_cast, which allows the programmer to strip the const qualifier, making any object modifiable.
The necessity of stripping the qualifier arises when using existing code and libraries that cannot be modified but which are not const-correct.
In the example above, if ptr references a global, local, or member variable declared as const, or an object allocated on the heap via new int const, the code is only correct if LibraryFunc really does not modify the value pointed to by ptr.
However, the initializer can use only constants like string constants and other literals, and is not allowed to use non-constant elements like variable names, whether the initializer elements are declared const or not, or whether the static duration variable is being declared const or not.
Writing into a const variable this way may work as intended, but it causes undefined behavior and seriously contradicts const-correctness: Another loophole[11] applies both to C and C++.
For this reason, Meyers argues that the default for member pointers and references should be "deep" const-ness, which could be overridden by a mutable qualifier when the pointee is not owned by the container, but this strategy would create compatibility issues with existing code.
The use of the type system to express constancy leads to various complexities and problems, and has accordingly been criticized and not adopted outside the narrow C family of C, C++, and D. Java and C#, which are heavily influenced by C and C++, both explicitly rejected const-style type qualifiers, instead expressing constancy by keywords that apply to the identifier (final in Java, const and readonly in C#).
This problem arises even for simple functions in the C standard library, notably strchr; this observation is credited by Ritchie to Tom Plum in the mid 1980s.
In C++ this is done via function overloading, typically implemented via a template, resulting in two functions, so that the return value has the same const-qualified type as the input:[b] These can in turn be defined by a template: In D this is handled via the inout keyword, which acts as a wildcard for const, immutable, or unqualified (variable), yielding:[14][c] However, in C neither of these is possible[d] since C does not have function overloading, and instead, this is handled by having a single function where the input is constant but the output is writable: This allows idiomatic C code but does strip the const qualifier if the input actually was const-qualified, violating type safety.
[18] const was then adopted in C as part of standardization, and appears in C89 (and subsequent versions) along with the other type qualifier, volatile.
[19] A further qualifier, noalias, was suggested at the December 1987 meeting of the X3J11 committee, but was rejected; its goal was ultimately fulfilled by the restrict keyword in C99.
[e] Other languages do not follow C/C++ in having constancy part of the type, though they often have superficially similar constructs and may use the const keyword.
C# has a const keyword, but with radically different and simpler semantics: it means a compile-time constant, and is not part of the type.
Nim has a const keyword similar to that of C#: it also declares a compile-time constant rather than forming part of the type.