const
mean in C?
What does const
mean in C?
const
is a keyword.
const
is a type qualifier. Type qualifiers are part of C types. In the type int const
, const
is a type qualifier, and int
is a type specifier. Here, const
qualifies the type int
. Qualifiers change the semantics of the type in some way. Other type qualifiers include volatile
and restrict
.
(Note you can also write const int
, which means the same thing as int const
. But should never write this. Always write const
in “postfix”, on the right-hand side of the type it is qualifying. That you can write const int
is a quirk of the C syntax which should not exist.)
How does int const
differ from int
? It’s simple: a value of type T const
cannot be assigned to, except when initialized. For example:
int main(void)
{
int i = 3; // OK
int const ci = 5; // OK; assignment at initialization
i = 7; // OK
ci = 9; // ERROR; assigning to `const` value
return 0;
}
You cannot assign to a const
value, even if assigning the same value:
int main(void)
{
int const ci = 5;
ci = 5; // ERROR, even though same value
return 0;
}
You cannot assign to a const
value, even if it was not initialized at declaration:
int main(void)
{
int const ci; // no initializer
ci = 5; // ERROR; cannot assign to `const` value even though uninitialized
return 0;
}
const
can sit in more complex types to express ideas like “pointer to an unassignable int”, or “unassignable pointer to an assignable int”, or “an array of unassignable integers”. Some examples:
typedef int const int_const; // An unassignable int
typedef int * int_ptr; // An assignable pointer to an assignable int
typedef int_const * int_const_ptr; // An assignable pointer to an unassignable int
typedef int * const int_ptr_const; // An unassignable pointer to an assignable int
typedef int_const * const int_const_ptr_const; // An unassignable pointer to an unassignable int
int main(void)
{
int i = 2; // An assignable int
int_const j = 3; // An unassignable int
i = j; // OK
// j = i; // ERROR; cannot assign to const
int_ptr pointer_to_int;
pointer_to_int = &i; // OK
// pointer_to_int = &j; // ERROR; `int_const` cannot be safely converted to `int`
int_const_ptr pointer_to_const_int;
pointer_to_const_int = &i; // OK! `int` can be converted to `const int`
pointer_to_const_int = &j; // OK
int_ptr_const const_pointer_to_int = &i; // OK
// int_ptr_const const_pointer_to_int_2 = &j; // ERROR; `int_const` cannot be converted to `int`
*const_pointer_to_int = 2; // OK, constness of pointer does not affect constness of pointee
// const_pointer_to_int = &i; // ERROR, cannot assign to const pointer
int_const_ptr_const const_pointer_to_const_int_1 = &i; // OK! `int` can be converted to `int const`
int_const_ptr_const const_pointer_to_const_int_2 = &j; // OK
return 0;
}
Note in particular that int
can be soundly converted to int const
. This is perhaps surprising: doesn’t this mean the compiler can make false assumptions? For example, if we tell the compiler that a value is const
, might the compiler not cache the value? As far as I understand, this is not the case, because const
doesn’t actually mean has a “constant value”. const
means “unassignable in this context”. Unassignable is not the same as immutable.
Some examples of const
in the standard library:
int atoi(const char * str); // atoi promises not to assign to the characters in the array
// qsort demands a comparator which does not modify the things it compares
void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*));
(Note that the standard library uses the horrible const char
construction. You should read it as char const
.)
I wrote this because I felt like it. This post is my own, and not associated with my employer.
Jim. Public speaking. Friends. Vidrio.